package logica.main;

import java.io.Console;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import logica.locacao.Extrato;
import logica.locacao.PlanoDeLocacao;
import logica.locacao.RegistroDeLocacao;
import logica.locacao.Seguro;
import logica.locacao.PlanoDeLocacao.TipoDeVeiculo;
import logica.locacao.RegistroDeLocacao.FormaDePagamento;
import logica.pessoa.Agencia;
import logica.pessoa.ClienteFisico;
import logica.pessoa.ClienteJuridico;
import logica.pessoa.Locador;
import logica.util.Data;
import logica.util.Mensagem;
import logica.util.Data.Mes;
import logica.veiculo.Acessorio;
import logica.veiculo.Automovel;
import logica.veiculo.Combustivel;
import logica.veiculo.Cor;
import logica.veiculo.Estado;
import logica.veiculo.Freio;
import logica.veiculo.Motocicleta;
import logica.veiculo.Potencia;
import logica.veiculo.Veiculo;
import logica.veiculo.Automovel.Porta;
import persistencia.GeradorDeExtrato;
import persistencia.GeradorDeLogs;
import persistencia.MecanismoDePersistenciaSeguro;
import util.Constantes;
import util.Endereco;
import util.TipoDeLogradouro;
import util.UF;
import criptografia.Encriptador;

/**
 * Classe de execucao do Sistema LocaLisa.
 * 
 * @author Equipe LocaLisa, Usa Quem Precisa
 *
 */
public class Main {
	
	//Constantes da primeira tela que ira aparecer
	private static final int LOGAR = 1;
	private static final int SAIR_DESLOGADO = 2;
	//Opcoes apos o login de gerente
	private static final int CADASTRAR = 1;
	private static final int EXCLUIR = 2;
	private static final int CONSULTAR = 3;
	private static final int EDITAR_GERENTE = 4;
	private static final int EDITAR_AGENCIA = 5;
	private static final int EFETUAR_LOCACAO = 6;
	private static final int EFETUAR_DEVOLUCAO = 7;
	private static final int ALTERAR_COMANDO_RETORNO = 8;
	private static final int LISTAR_ULTIMAS_ACOES = 9;
	private static final int DESLOGAR = 10;
	private static final int SALVAR = 11;
	private static final int SAIR_LOGADO = 12;
	//Opcoes apos o login de locador
	private static final int CONSULTAR2 = 1;
	private static final int EFETUAR_LOCACAO2 = 2;
	private static final int EFETUAR_DEVOLUCAO2 = 3;
	private static final int LISTAR_ULTIMAS_ACOES2 = 4;
	private static final int DESLOGAR2 = 5;
	private static final int SALVAR2 = 6;
	private static final int SAIR_LOGADO2 = 7;

	//Formas de Pagamento
	private static final int DIARIAS = 1;
	private static final int QUILOMETRAGEM = 2;
	
	//Opcoes que podem ser cadastradas/excluidas
	private static final int LOCADOR = 1;
	private static final int CLIENTE = 2;
	private static final int VEICULO = 3;
	private static final int PLANO = 4;
	private static final int VOLTAR_AGENCIA = 5; //VOLTAR OU AGENCIA
	private static final int GERENTE = 6;
	private static final int LOCACOES = 7;
	private static final int DEVOLUCOES = 8;
	private static final int VOLTAR = 9;
	
	//Tipos de Cliente
	private static final int CLIENTE_FISICO = 1;
	private static final int CLIENTE_JURIDICO = 2;
	
	//Tipos de Veiculo
	private static final int AUTOMOVEL = 1;
	private static final int MOTOCICLETA = 2;
	
	//Escolhas
	private static final int SIM = 1;
	private static final int NAO = 2;
	
	private static Scanner scanner = new Scanner(System.in);
	private static String comando_retorno = "voltar";
	private static boolean sair;
	
	private static Locador root; //Gerente Administrador Do Sistema, nao deve poder ser deletado nunca, mas seus dados podem ser alterados
	private static Locador locadorAtual; //Usuario corrente do sistema
	private static Agencia agenciaAtual; //Agencia do Sistema
	private static GeradorDeLogs geradorDeLog;//Objeto que gera os logs
	private static Extrato extratoDaLocacao; //Ponteiro dos extratos de locacao
	
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaVeiculos;
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaPlanoDeLocacao;
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaLocador;
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaClientesFisico;
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaClientesJuridicos;
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaRegistroDeLocacao;
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaRegistroDeDevolucao;
	private static MecanismoDePersistenciaSeguro mecanismoDePersistenciaAgencia;
	
	private static List<Locador> usuariosLista; //Lista de usuarios do Sistema
	private static List<Veiculo> automoveisLista; //Lista de veiculos do Sistema
	private static List<Veiculo> motocicletasLista; //Lista de veiculos do Sistema
	private static List<PlanoDeLocacao> planosLista; //Lista de planos de locacao do Sistema
	private static List<ClienteFisico> clientesFisicosLista; //Lista de clientes fisicos cadastrados
	private static List<ClienteJuridico> clientesJuridicosLista; //Lista de clientes juridicos cadastrados
	private static List<RegistroDeLocacao> registrosDeLocacaoLista; //Lista dos registros de locacao
	private static List<RegistroDeLocacao> registrosDeDevolucaoLista;	//Lista dos registros de devolucao
	
	/**
	 * Execucao Principal do Programa.
	 * @param naoUsado - Programa nao recebe nada como parametro na linha de comando
	 */
	@SuppressWarnings("unchecked")
	public static void main(String naoUsado[]) {
		
		try{
			
			geradorDeLog = new GeradorDeLogs();//Instancia do gerador de logs
			
			mecanismoDePersistenciaVeiculos = new MecanismoDePersistenciaSeguro("arquivos/automoveis.ser");
			automoveisLista = (ArrayList<Veiculo>) mecanismoDePersistenciaVeiculos.recuperaDoArquivo();
			if(automoveisLista == null){
				automoveisLista = new ArrayList<Veiculo>();
			}

			mecanismoDePersistenciaVeiculos = new MecanismoDePersistenciaSeguro("arquivos/motocicletas.ser");
			motocicletasLista = (ArrayList<Veiculo>) mecanismoDePersistenciaVeiculos.recuperaDoArquivo();
			if(motocicletasLista == null){
				motocicletasLista = new ArrayList<Veiculo>();
			}			
			
			mecanismoDePersistenciaPlanoDeLocacao = new MecanismoDePersistenciaSeguro("arquivos/planodelocacao.ser");
			planosLista = (ArrayList<PlanoDeLocacao>) mecanismoDePersistenciaPlanoDeLocacao.recuperaDoArquivo();
			if(planosLista == null){
				planosLista = new ArrayList<PlanoDeLocacao>();
			}
			
			mecanismoDePersistenciaLocador = new MecanismoDePersistenciaSeguro("arquivos/locadores.ser");
			usuariosLista = (ArrayList<Locador>) mecanismoDePersistenciaLocador.recuperaDoArquivo();
			if(usuariosLista == null){
				usuariosLista = new ArrayList<Locador>();
			}
			
			if(usuariosLista.isEmpty()){
				
				root = new Locador();
				root.setNome("Administrador do Sistema");
				root.setTelefone("(83) 88888888");
				root.setEmail("root@localisa.com");
				Endereco enderecoDefault = new Endereco();
				enderecoDefault.setEstado(UF.PB);
				enderecoDefault.setCidade("Cidade");
				enderecoDefault.setBairro("Bairro");
				enderecoDefault.setTipoDeLogradouro(TipoDeLogradouro.Rua);
				enderecoDefault.setNumero(1);
				enderecoDefault.setCep("58310000");
				enderecoDefault.setObs("Observacoes adicionais");
				root.setEndereco(enderecoDefault);
				root.setCPF("10101010101");
				root.setRG("10101010101");
				root.setDataDeNascimento(new Data());
				root.setLogin("admin");
				root.setSenha("admin");
				root.setEhGerente(true);
				usuariosLista.add(root);
				geradorDeLog.escreveLog("Usuario "+root.getLogin()+" foi cadastrado");
				
			}else{
				for ( Locador locador : usuariosLista ){
					if ( locador.getEhGerente() ){
						root = locador;
					}
				}
			}
							
			mecanismoDePersistenciaClientesFisico = new MecanismoDePersistenciaSeguro("arquivos/clientefisico.ser");
			clientesFisicosLista = (ArrayList<ClienteFisico>) mecanismoDePersistenciaClientesFisico.recuperaDoArquivo(); 
			if(clientesFisicosLista == null){
				clientesFisicosLista = new ArrayList<ClienteFisico>();
			}
			
			mecanismoDePersistenciaClientesJuridicos = new MecanismoDePersistenciaSeguro("arquivos/clientejuridico.ser");
			clientesJuridicosLista = (ArrayList<ClienteJuridico>) mecanismoDePersistenciaClientesJuridicos.recuperaDoArquivo();
			if(clientesJuridicosLista == null){
				clientesJuridicosLista = new ArrayList<ClienteJuridico>();
			}

			mecanismoDePersistenciaRegistroDeLocacao = new MecanismoDePersistenciaSeguro("arquivos/registrodelocacao.ser");
			registrosDeLocacaoLista = (ArrayList<RegistroDeLocacao>) mecanismoDePersistenciaRegistroDeLocacao.recuperaDoArquivo(); 
			if(registrosDeLocacaoLista == null){
				registrosDeLocacaoLista = new ArrayList<RegistroDeLocacao>();
			}

			mecanismoDePersistenciaRegistroDeDevolucao = new MecanismoDePersistenciaSeguro("arquivos/registrodedevolucao.ser");
			registrosDeDevolucaoLista = (ArrayList<RegistroDeLocacao>) mecanismoDePersistenciaRegistroDeDevolucao.recuperaDoArquivo(); 
			if(registrosDeDevolucaoLista == null){
				registrosDeDevolucaoLista = new ArrayList<RegistroDeLocacao>();
			}
			
			mecanismoDePersistenciaAgencia = new MecanismoDePersistenciaSeguro("arquivos/agencia.ser");
			agenciaAtual = (Agencia) mecanismoDePersistenciaAgencia.recuperaObjetoNoArquivo();
			if ( agenciaAtual == null ){
				agenciaAtual = new Agencia();
				agenciaAtual.setCNPJ("01010101010101");
				agenciaAtual.setEmail("agenciadeffault@localisa.com");
				Endereco enderecoDefault2 = new Endereco();
				enderecoDefault2.setEstado(UF.PB);
				enderecoDefault2.setCidade("Cidade");
				enderecoDefault2.setBairro("Bairro");
				enderecoDefault2.setTipoDeLogradouro(TipoDeLogradouro.Rua);
				enderecoDefault2.setNumero(1);
				enderecoDefault2.setCep("58310000");
				enderecoDefault2.setObs("Observacoes adicionais");
				root.setEndereco(enderecoDefault2);
				agenciaAtual.setEndereco(enderecoDefault2);
				agenciaAtual.setInscricaoEstadual("101010101010");
				agenciaAtual.setNomeFantasia("Default");
				agenciaAtual.setRazaoSocial("Fulano Responsavel Pela Agencia Default");
				agenciaAtual.setTelefone("(83) 88888888");
			}
			
			geradorDeLog.escreveLog("Programa Iniciado");
			
		}catch(Exception e){
			System.out.println(e.getMessage());
			System.exit(0);
		}
		
		Data hoje = new Data();

		String boas_vindas = Constantes.LOGO+"\t\t\t     Bem-vindo ao Sistema Localisa!\n\t\t\t    --AGENCIA "+agenciaAtual.getNomeFantasia()+"\n\t\t\t    <Hoje eh "+hoje.getDataPorExtenso()+">\n";
		
		String statusDaAgencia = String.format("\n \t %03d funcionarios trabalham nesta agencia\n \t %03d clientes cadastrados\n \t %03d veiculos adquiridos\n \t %03d planos de locacao existentes\n \t %03d locacoes pendentes\n", 
				usuariosLista.size(), clientesFisicosLista.size()+clientesJuridicosLista.size(), automoveisLista.size()+motocicletasLista.size(), planosLista.size(), registrosDeLocacaoLista.size());
		
		System.out.print(preSeparadorDeEtapas()+boas_vindas+statusDaAgencia);
		
		while (!sair){
			
			if ( locadorAtual == null ){
				switch(escolherOpcao(preSeparadorDeEtapas()+statusUsuarioLogado()+posSeparadorDeEtapas()+
						"\n \t Escolha uma opcao a seguir:\n \t [1]Logar\t[2]Sair\n",2)){
					case LOGAR:{
						try{
							locadorAtual = fazLogin(); //Faz o login no sistema, e retorna o locador logado
							geradorDeLog.escreveLog("Usuario "+locadorAtual.getLogin()+" logou-se");
						}
						catch ( Exception e ){
							System.out.println(e.getMessage());
						}
						break;
					}
					case SAIR_DESLOGADO:{
						try {
							
							salvandoTodosOsDados();
									
							geradorDeLog.escreveLog("Programa Finalizado");
							
						} catch (Exception e) {
							System.out.println(e.getMessage());
						}
						System.out.println(preSeparadorDeEtapas()+Constantes.SLOGAN+preSeparadorDeEtapas());
						sair = true;
						System.out.println("\n \t Saindo do sistema...\n");
						break;
					}
				}
			}
			else if ( locadorAtual.getEhGerente() ){
				boolean cadastrar = false;
				boolean excluir = false;
				boolean consultar = false;
				
				switch(escolherOpcao(preSeparadorDeEtapas()+statusUsuarioLogado()+posSeparadorDeEtapas()+
						"\n \t Escolha uma opcao a seguir:\n \t [1]  Cadastrar...\n \t [2]  Excluir...\n \t [3]  Consultar...\n \t [4]  Editar Gerente\n \t [5]  Editar Agencia\n \t [6]  Efetuar Locacao\n \t [7]  Efetuar Devolucao\n \t [8]  Alterar Comando de Retorno\n \t [9]  Listar Ultimas Acoes\n \t [10] Deslogar\n \t [11] Salvar\n\t [12] Salvar e Sair\n",12)){
					case CADASTRAR:{
						System.out.println(Mensagem.INFO_COMANDO_RETORNO);
						cadastrar = true;
						break;
					}
					case EXCLUIR:{
						System.out.println(Mensagem.INFO_COMANDO_RETORNO);
						excluir = true;
						break;
					}
					case CONSULTAR:{
						consultar = true;
						break;
					}
					case EDITAR_GERENTE:{
						try{
							System.out.println(Mensagem.INFO_COMANDO_RETORNO);
							editaGerente();
							System.out.println(Mensagem.MENSAGEM_EDICAO_BEM_SUCEDIDA);
						}
						catch (Exception e){
							System.out.println(Mensagem.MENSAGEM_EDICAO_MAL_SUCEDIDA);
							System.out.println(e.getMessage());
						}
						break;
					}
					case EDITAR_AGENCIA:{
						try{
							System.out.println(Mensagem.INFO_COMANDO_RETORNO);
							editaAgencia();
							System.out.println(Mensagem.MENSAGEM_EDICAO_BEM_SUCEDIDA);
						}
						catch (Exception e){
							System.out.println(Mensagem.MENSAGEM_EDICAO_MAL_SUCEDIDA);
							System.out.println(e.getMessage());
						}
						break;
					}
					case EFETUAR_LOCACAO:{
						try{
							System.out.println(Mensagem.INFO_COMANDO_RETORNO);
							efetuaLocacao();
							System.out.println(Mensagem.MENSAGEM_LOCACAO_BEM_SUCEDIDA);
						}
						catch (Exception e){
							System.out.println(Mensagem.MENSAGEM_LOCACAO_MAL_SUCEDIDA);
							System.out.println(e.getMessage());
						}
						break;
					}
					case EFETUAR_DEVOLUCAO:{
						try{
							System.out.println(Mensagem.INFO_COMANDO_RETORNO);
							efetuaDevolucao();
							System.out.println(Mensagem.MENSAGEM_DEVOLUCAO_BEM_SUCEDIDA);
						}
						catch (Exception e){
							System.out.println(Mensagem.MENSAGEM_DEVOLUCAO_MAL_SUCEDIDA);
							System.out.println(e.getMessage());
						}
						break;
					}
					case ALTERAR_COMANDO_RETORNO:{
						try{
							while ( true ){
								String novoComando = retornaStringCorreto(Mensagem.FORMULARIO_COMANDO_RETORNO);
								boolean existe = false;
								for ( Locador user : usuariosLista ){
									Encriptador encriptor = new Encriptador();
									if ( user.getLogin().equals(novoComando) || user.getSenha().equals(encriptor.geraHashParaSenha(novoComando)) ){
										existe = true;
									}
								}
								if ( !existe ){
									comando_retorno = novoComando;
									System.out.println(Mensagem.MENSAGEM_EDICAO_BEM_SUCEDIDA);
									break;
								}
								System.out.println("\n \t <Comando nao pode ser setado para esse!>\n \t <Conflitos com dados do sistema!>");
							}
						}
						catch(Exception e){
							System.out.println(Mensagem.MENSAGEM_EDICAO_MAL_SUCEDIDA);
							System.out.println(e.getMessage());
						}
						break;
					}
					case LISTAR_ULTIMAS_ACOES:{
						try{
							int qtde = retornaInteiroCorreto(Mensagem.FORMULARIO_ACOES);
							System.out.println(geradorDeLog.ultimasAcoes(qtde));
						}
						catch(Exception e){
							System.out.println(e.getMessage());
						}
						break;
					}
					case DESLOGAR:{
						try {
							geradorDeLog.escreveLog("Usuario "+locadorAtual.getLogin()+" Matricula " +locadorAtual.getMatricula()+" deslogou-se");
						} catch (Exception e) {
							System.out.println(e.getMessage());
						}
						locadorAtual = null;
						break;
					}
					case SALVAR:{
						try {
							salvandoTodosOsDados();
						} catch (Exception e) {
							System.out.println(e.getMessage());
						}
						break;
					}
					case SAIR_LOGADO:{
						try {
							salvandoTodosOsDados();
							geradorDeLog.escreveLog("Usuario "+locadorAtual.getLogin()+" Matricula " +locadorAtual.getMatricula()+" deslogou-se");
							geradorDeLog.escreveLog("Programa Finalizado");
						} catch (Exception e) {
							System.out.println(e.getMessage());
						}
						System.out.println(preSeparadorDeEtapas()+Constantes.SLOGAN+preSeparadorDeEtapas());
						sair = true;
						System.out.println("\n \t Saindo do sistema...\n");
						break;
					}
				}
				
				while ( cadastrar || excluir || consultar ){
					StringBuilder mensagemDeGuia = new StringBuilder();
					mensagemDeGuia.append(preSeparadorDeEtapas()+statusUsuarioLogado()+posSeparadorDeEtapas());
					if ( cadastrar ){
						mensagemDeGuia.append("\n \t O que voce deseja cadastrar: \n");
					}
					else if ( excluir ){
						mensagemDeGuia.append("\n \t O que voce deseja excluir: \n");
					}
					else if ( consultar ){
						mensagemDeGuia.append("\n \t O que voce deseja consultar: \n");
					}
					
					switch((consultar?escolherOpcao(mensagemDeGuia.toString()+
							"\n \t [1]Locador  [2]Cliente  [3]Veiculo  [4]Plano  [5]Agencia\n \t [6]Gerente  [7]Locacoes Pendentes  [8]Registros de Devolucoes\n \t [9]Voltar\n",9)
							:escolherOpcao(mensagemDeGuia.toString()+
									"\n \t [1]Locador  [2]Cliente  [3]Veiculo  [4]Plano  [5]Voltar\n",5))){
						case LOCADOR:{
								if ( cadastrar ){
									try{
										cadastrarLocador();
										System.out.println(Mensagem.MENSAGEM_CADASTRO_BEM_SUCEDIDO);
									}
									catch (Exception e){
										System.out.println(Mensagem.MENSAGEM_CADASTRO_MAL_SUCEDIDO);
										System.out.println(e.getMessage());
									}
								}
								else if ( excluir ){
									try{
										excluirLocador();
										System.out.println(Mensagem.MENSAGEM_EXCLUSAO_BEM_SUCEDIDA);
									}
									catch (Exception e){
										System.out.println(Mensagem.MENSAGEM_EXCLUSAO_MAL_SUCEDIDA);
										System.out.println(e.getMessage());
									}
								}
								else if ( consultar ){
									try{
										System.out.println(listarObjetosNaLista(usuariosLista));
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
								}
								break;
						}
						case CLIENTE:{
								
								StringBuilder mensagemDeGuia2 = new StringBuilder();
								
								if ( cadastrar ){
									mensagemDeGuia2.append("\n \t Que tipo de cliente voce deseja cadastrar: \n");
								}
								
								else  if ( excluir ){
									mensagemDeGuia2.append("\n \t Que tipo de cliente voce deseja excluir: \n");
								}
								
								switch(escolherOpcao(mensagemDeGuia2.toString()+"\n \t [1]Cliente Fisico\t[2]Cliente Juridico\n",2)){
								
								case CLIENTE_FISICO:{
									if ( cadastrar ){
										try{
											cadastraClienteFisico();
											System.out.println(Mensagem.MENSAGEM_CADASTRO_BEM_SUCEDIDO);
										}
										catch (Exception e){
											System.out.println(Mensagem.MENSAGEM_CADASTRO_MAL_SUCEDIDO);
											System.out.println(e.getMessage());
										}
									}
									else  if ( excluir ){
										try{
											excluirObjetoNaLista(clientesFisicosLista);
											System.out.println(Mensagem.MENSAGEM_EXCLUSAO_BEM_SUCEDIDA);
										}
										catch (Exception e){
											System.out.println(Mensagem.MENSAGEM_EXCLUSAO_MAL_SUCEDIDA);
											System.out.println(e.getMessage());
										}
									}
									else if ( consultar ){
										try{
											System.out.println(listarObjetosNaLista(clientesFisicosLista));
										}
										catch (Exception e){
											System.out.println(e.getMessage());
										}
									}
									break;
								}
								
								case CLIENTE_JURIDICO:{
									if ( cadastrar ){
										try{
											cadastraClienteJuridico();
											System.out.println(Mensagem.MENSAGEM_CADASTRO_BEM_SUCEDIDO);
										}
										catch (Exception e){
											System.out.println(Mensagem.MENSAGEM_CADASTRO_MAL_SUCEDIDO);
											System.out.println(e.getMessage());
										}
									}
									else  if ( excluir ){
										try{
											excluirObjetoNaLista(clientesJuridicosLista);
											System.out.println(Mensagem.MENSAGEM_EXCLUSAO_BEM_SUCEDIDA);
										}
										catch (Exception e){
											System.out.println(Mensagem.MENSAGEM_EXCLUSAO_MAL_SUCEDIDA);
											System.out.println(e.getMessage());
										}
									}
									else if ( consultar ){
										try{
											System.out.println(listarObjetosNaLista(clientesJuridicosLista));
										}
										catch (Exception e){
											System.out.println(e.getMessage());
										}
									}
									break;
								}
							}
							break;
						}
						case VEICULO:{
							StringBuilder mensagemDeGuia3 = new StringBuilder();
							if ( cadastrar ){
								mensagemDeGuia3.append("\n \t Que tipo de veiculo voce deseja cadastrar: \n");
							}
							else if ( excluir ){
								mensagemDeGuia3.append("\n \t Que tipo de veiculo voce deseja excluir: \n");
							}
							if ( consultar ){
								try{
									List<Veiculo> temp = new ArrayList<Veiculo>();
									temp.addAll(automoveisLista);
									temp.addAll(motocicletasLista);
									System.out.println(listarObjetosNaLista(temp));
								}
								catch (Exception e){
									System.out.println(e.getMessage());
								}
							}
							else{
								switch(escolherOpcao(mensagemDeGuia3.toString()+"\n \t [1]Automovel\t[2]Motocicleta\n",2)){
									case AUTOMOVEL:{
										if ( cadastrar ){
											try{
												cadastraAutomovel();
												System.out.println(Mensagem.MENSAGEM_CADASTRO_BEM_SUCEDIDO);
						
											}catch(Exception e){
												System.out.println(e.getMessage());
												System.out.println(Mensagem.MENSAGEM_CADASTRO_MAL_SUCEDIDO);
											}
										}
										else  if ( excluir ){
											try{
												excluirAutomovel();
												System.out.println(Mensagem.MENSAGEM_EXCLUSAO_BEM_SUCEDIDA);
											}catch(Exception e){
												System.out.println(Mensagem.MENSAGEM_EXCLUSAO_MAL_SUCEDIDA);
												System.out.println(e.getMessage());
											}
										}//Excluir Automovel
										break;
									}
									case MOTOCICLETA:{
										if ( cadastrar ){
											try{
												cadastraMotocicleta();
												System.out.println(Mensagem.MENSAGEM_CADASTRO_BEM_SUCEDIDO);
																				
											}catch(Exception e){
												System.out.println(e.getMessage());
												System.out.println(Mensagem.MENSAGEM_CADASTRO_MAL_SUCEDIDO);
											}
										}	
										else  if ( excluir ){
											try{
												excluirMotocicleta();
												System.out.println(Mensagem.MENSAGEM_EXCLUSAO_BEM_SUCEDIDA);
											}catch(Exception e){
												System.out.println(Mensagem.MENSAGEM_EXCLUSAO_MAL_SUCEDIDA);
												System.out.println(e.getMessage());
											}
										}//Excluir Motocicleta
										break;
									}
								}
							}
							break;
						}
						case PLANO:{
							if ( cadastrar ){
								try{
									cadastraPlano();
									System.out.println(Mensagem.MENSAGEM_CADASTRO_BEM_SUCEDIDO);
									
								}
								catch ( Exception e ){
									System.out.println(Mensagem.MENSAGEM_CADASTRO_MAL_SUCEDIDO);
									System.out.println(e.getMessage());
								}
							}
							else  if ( excluir ){
								try{
									excluirObjetoNaLista(planosLista);
									System.out.println(Mensagem.MENSAGEM_EXCLUSAO_BEM_SUCEDIDA);
								}
								catch ( Exception e ){
									System.out.println(Mensagem.MENSAGEM_EXCLUSAO_MAL_SUCEDIDA);
									System.out.println(e.getMessage());
								}
							}
							else if ( consultar ){
								try{
									System.out.println(listarObjetosNaLista(planosLista));
								}
								catch (Exception e){
									System.out.println(e.getMessage());
								}
							}
							break;
						}
						case VOLTAR_AGENCIA:{ //VOLTAR OU AGENCIA
							if ( cadastrar ){
								System.out.println("\n \t Operacoes de cadastro finalizadas.\n");
								cadastrar = false;
							}
							else if ( excluir ){
								System.out.println("\n \t Operacoes de exclusao finalizadas.\n");
								excluir = false;
							}
							else if ( consultar ){
								try{
									System.out.println(agenciaAtual);
								}
								catch (Exception e){
									System.out.println(e.getMessage());
								}
							}
							break;
						}
						case GERENTE:{
							if ( consultar ){
								try{
									System.out.println(root);
								}
								catch (Exception e){
									System.out.println(e.getMessage());
								}
							}
							break;
						}
						case LOCACOES:{
							if ( consultar ){
								try{
									System.out.println(listarObjetosNaLista(registrosDeLocacaoLista));
								}
								catch (Exception e){
									System.out.println(e.getMessage());
								}
							}
							break;
						}
						case DEVOLUCOES:{
							if ( consultar ){
								try{
									System.out.println(listarObjetosNaLista(registrosDeDevolucaoLista));
								}
								catch (Exception e){
									System.out.println(e.getMessage());
								}
							}
							break;
						}
						case VOLTAR:{
							if ( consultar ){
								System.out.println("\n \t Operacoes de consulta finalizadas.\n");
								consultar = false;
							}
							break;
						}
					}
				}
			}
			else{
				switch(escolherOpcao(preSeparadorDeEtapas()+statusUsuarioLogado()+posSeparadorDeEtapas()+
						"\n \t Escolha uma opcao a seguir:\n \t [1]  Consultar...\n \t [2]  Efetuar Locacao\n \t [3]  Efetuar Devolucao\n \t [4]  Listar Ultimas Acoes\n \t [5]  Deslogar\n \t [6]  Salvar\n \t [7]  Salvar e Sair\n",7)){
					case CONSULTAR2:{
						boolean consultar = true;
						while ( consultar ){
							switch(escolherOpcao("\n \t O que voce deseja consultar: "+
							"\n \t [1]Locador  [2]Cliente  [3]Veiculo  [4]Plano  [5]Agencia\n \t [6]Gerente  [7]Locacoes Pendentes  [8]Registros de Devolucoes\n \t [9]Voltar\n",9)){
								case LOCADOR:{
									try{
										System.out.println(listarObjetosNaLista(usuariosLista));
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
									break;
								}
								case CLIENTE:{
									switch(escolherOpcao("\n \t Escolha o que voce deseja consultar: \n \t [1]Cliente Fisico\t[2]Cliente Juridico\n",2)){
										case CLIENTE_FISICO:{
											try{
												System.out.println(listarObjetosNaLista(clientesFisicosLista));
											}
											catch (Exception e){
												System.out.println(e.getMessage());
											}
											break;
										}
										case CLIENTE_JURIDICO:{
											try{
												System.out.println(listarObjetosNaLista(clientesJuridicosLista));
											}
											catch (Exception e){
												System.out.println(e.getMessage());
											}
											break;
										}
									}
									break;
								}
								case VEICULO:{
									try{
										List<Veiculo> temp = new ArrayList<Veiculo>();
										temp.addAll(automoveisLista);
										temp.addAll(motocicletasLista);
										System.out.println(listarObjetosNaLista(temp));
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
									break;
								}
								case PLANO:{
									try{
										System.out.println(listarObjetosNaLista(planosLista));
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
									break;
								}
								case VOLTAR_AGENCIA:{
									try{
										System.out.println(agenciaAtual);
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
									break;
								}
								case GERENTE:{
									try{
										System.out.println(root);
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
									break;
								}
								case LOCACOES:{
									try{
										System.out.println(listarObjetosNaLista(registrosDeLocacaoLista));
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
									break;
								}
								case DEVOLUCOES:{
									try{
										System.out.println(listarObjetosNaLista(registrosDeDevolucaoLista));
									}
									catch (Exception e){
										System.out.println(e.getMessage());
									}
									break;
								}
								case VOLTAR:{
									System.out.println("\n \t Operacoes de consulta finalizadas.\n");
									consultar = false;
									break;
								}
							}
						}
						break;
					}
					case EFETUAR_LOCACAO2:{
						try{
							efetuaLocacao();
							System.out.println(Mensagem.MENSAGEM_LOCACAO_BEM_SUCEDIDA);
						}
						catch (Exception e){
							System.out.println(Mensagem.MENSAGEM_LOCACAO_MAL_SUCEDIDA);
							System.out.println(e.getMessage());
						}
						break;
					}
					case EFETUAR_DEVOLUCAO2:{
						try{
							efetuaDevolucao();
							System.out.println(Mensagem.MENSAGEM_DEVOLUCAO_BEM_SUCEDIDA);
						}
						catch (Exception e){
							System.out.println(Mensagem.MENSAGEM_DEVOLUCAO_MAL_SUCEDIDA);
							System.out.println(e.getMessage());
						}
						break;
					}
					case LISTAR_ULTIMAS_ACOES2:{
						try{
							int qtde = retornaInteiroCorreto(Mensagem.FORMULARIO_ACOES);
							System.out.println(geradorDeLog.ultimasAcoes(qtde));
						}
						catch(Exception e){
							System.out.println(e.getMessage());
						}
						break;
					}
					case DESLOGAR2:{
						try {
							geradorDeLog.escreveLog("Usuario "+locadorAtual.getLogin()+" Matricula " +locadorAtual.getMatricula()+" deslogou-se");
						} catch (Exception e) {
							System.out.println(e.getMessage());
						}
						locadorAtual = null;
						break;
					}
					case SALVAR2:{
						try {
							salvandoTodosOsDados();
						} catch (Exception e) {
							System.out.println(e.getMessage());
						}
						break;
					}
					case SAIR_LOGADO2:{
						try {
							salvandoTodosOsDados();
							geradorDeLog.escreveLog("Usuario "+locadorAtual.getLogin()+" Matricula " +locadorAtual.getMatricula()+" deslogou-se");
							geradorDeLog.escreveLog("Programa Finalizado");
						} catch (Exception e) {
							System.out.println(e.getMessage());
						}
						System.out.println(preSeparadorDeEtapas()+Constantes.SLOGAN+preSeparadorDeEtapas());
						sair = true;
						System.out.println("\n \t Saindo do sistema...\n");
						break;
					}
				}
			}
		}
		System.exit(0);
	}

	@SuppressWarnings("unchecked")
	private static void salvandoTodosOsDados() throws Exception{
		
		geradorDeLog.escreveLog("Gravando dados");
		if(mecanismoDePersistenciaVeiculos.persisteNoArquivo((ArrayList) automoveisLista)){
			System.out.println("\n \t Gravando... Veiculos");
		}
		if(mecanismoDePersistenciaVeiculos.persisteNoArquivo((ArrayList) motocicletasLista)){
			System.out.println("\n \t Gravando... Motocicletas");
		}
		if(mecanismoDePersistenciaPlanoDeLocacao.persisteNoArquivo((ArrayList) planosLista)){
			System.out.println("\n \t Gravando... Planos");
		}
		if(mecanismoDePersistenciaLocador.persisteNoArquivo((ArrayList) usuariosLista)){
			System.out.println("\n \t Gravando... Gerente e locadores");
		}
		if(mecanismoDePersistenciaClientesFisico.persisteNoArquivo((ArrayList) clientesFisicosLista)){
			System.out.println("\n \t Gravando... Clientes pessoa fisica");
		}
		if(mecanismoDePersistenciaClientesJuridicos.persisteNoArquivo((ArrayList) clientesJuridicosLista)){
			System.out.println("\n \t Gravando... Clientes pessoa juridica");
		}
		if(mecanismoDePersistenciaRegistroDeLocacao.persisteNoArquivo((ArrayList) registrosDeLocacaoLista)){
			System.out.println("\n \t Gravando... Registros de locacao");
		}
		if(mecanismoDePersistenciaRegistroDeDevolucao.persisteNoArquivo((ArrayList) registrosDeDevolucaoLista)){
			System.out.println("\n \t Gravando... Registros de devolucao");
		}

		mecanismoDePersistenciaAgencia.persisteObjetoNoArquivo(agenciaAtual);
		System.out.println("\n \t Gravando... Informacoes da agencia\n");
		
		System.out.println(String.format("\n \t %03d funcionarios trabalham nesta agencia\n \t %03d clientes cadastrados\n \t %03d veiculos adquiridos\n \t %03d planos de locacao existentes\n \t %03d locacoes pendentes\n", 
				usuariosLista.size(), clientesFisicosLista.size()+clientesJuridicosLista.size(), automoveisLista.size()+motocicletasLista.size(), planosLista.size(), registrosDeLocacaoLista.size()));
		
	}

	
	/**
	 * Retorna um separador de etapas para ser inserido no comeco da etapa, dividindo cada etapa na tela.
	 * @author Guilherme Santos
	 */
	private static String preSeparadorDeEtapas(){
		return "\n\t==============================================================\n";
	}
	
	/**
	 * Retorna um separador de etapas para ser inserido no fim da etapa, dividindo cada etapa na tela.
	 * @author Guilherme Santos
	 */
	private static String posSeparadorDeEtapas(){
		return "\n\t==============================================================\n\t==============================================================\n";
	}
	
	/**
	 * Retorna uma mensagem que indica se ha ou nao um usuario logado.
	 * @return Uma mensagem indicando se ha ou nao um usuario logado.
	 */
	private static String statusUsuarioLogado(){
		if ( locadorAtual == null ){
			return String.format("%70s", "--AGENCIA "+agenciaAtual.getNomeFantasia())+"\n\n \t <Nenhum usuario logado!>\n \t (Se logue e bom trabalho!)";
		}
		else{
			return String.format("%70s", "--AGENCIA "+agenciaAtual.getNomeFantasia())+"\n\n \t <"+locadorAtual.getLogin()+" esta logado!>\n \t ("+locadorAtual.getNome()+")";
		}
	}
	
	/**
	 * Verifica se o usuario deseja voltar a operacao/opcao.
	 * @author Guilherme Santos
	 * @param comando
	 * @throws Exception
	 */
	public static void verificaSeCancelou(String comando) throws Exception{
		if ( comando.equals(comando_retorno) ){
			throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
		}
	}
	
	/**
	 * Mostra uma mensagem e pede para entrar com uma opcao em um certo limite, como reacao a mensagem
	 * @param mensagem
	 * @param maximo
	 * @return int
	 * @throws Exception 
	 */
	public static int escolherOpcao(String mensagem, int maximo) {
				
		System.out.print(mensagem+"\n\t>: ");

		String escolhidoString = scanner.nextLine(); 
		
		if (escolhidoString.isEmpty()){
			System.out.println("\n \t <Voce deve inserir alguma entrada!>\n");
			return escolherOpcao(mensagem, maximo);
		}
		
		try{
			verificaSeCancelou(escolhidoString);
		}
		catch (Exception e){
			System.out.println("\n \t <Comando de retorno nao funciona aqui!>");
			return escolherOpcao(mensagem, maximo);
		}
		
		for (int i=0; i<escolhidoString.length(); i++){
			if(!Character.isDigit(escolhidoString.charAt(i))){
				System.out.println("\n \t <Entrada nao eh um inteiro valido!>\n");
				return escolherOpcao(mensagem, maximo);
			}			
		}		
		
		int escolhidoInt = Integer.parseInt(escolhidoString);
		
		if ( escolhidoInt <= 0 || escolhidoInt > maximo ){
			System.out.println("\n \t <Entrada eh um inteiro valido mas nao esta no intervalo de 1 a "+maximo+"!>\n");
			return escolherOpcao(mensagem, maximo);
		}
		
		return escolhidoInt;
	
	}
		
	/**
	 * Pede login e senha e faz o login, caso estejam corretos, ou trata caso nao existam
	 * @return
	 */
	private static Locador fazLogin() throws Exception{
		
		String login = retornaStringCorreto(Mensagem.FORMULARIO_LOGIN);
		
		String senha = retornaSenha(Mensagem.FORMULARIO_SENHA);
		
		Iterator<Locador> iterador = usuariosLista.iterator();
		
		while(iterador.hasNext()){
			
			Locador usuarioAtual = iterador.next();
			
			if(usuarioAtual.getLogin().equals(login)){
				
				Encriptador encriptor = new Encriptador();
				
				if ( usuarioAtual.getSenha().equals( encriptor.geraHashParaSenha(senha) )){
					System.out.println("\n \t Login realizado com sucesso!");
					return usuarioAtual;
				}
				
			}
		}
		System.out.println("\n \t <Login ou senha nao existem!>");
		return fazLogin();
	}
	
	/**
	 * Verifica se uma string entrou de maneira legal para ser tratada pelos construtores e pelos sets
	 * @param mensagem
	 * @param input
	 * @return String
	 * @throws Exception
	 */
	private static String retornaStringCorreto(String mensagem) throws Exception{
		
		System.out.print(mensagem);
		String input = scanner.nextLine();
		
		if ( mensagem.equals(Mensagem.FORMULARIO_OBSERVACAO) ){
			scanner = new Scanner(System.in);
			if ( input.equals(comando_retorno) ){
				throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
			}
			else if ( input.trim().isEmpty() ){
				return " ";
			}
		}
		
		while(!validaString(input)){
			System.out.println("\n \t <Digite novamente!>");
			System.out.print(mensagem);
			input = scanner.nextLine();
		}
		
		return input;
	}
	
	private static String retornaSenha(String mensagem) throws Exception{
		
		System.out.print(mensagem);
		Console input = System.console();
		char[] senha = input.readPassword();
		
//		String input = scanner.nextLine();
		
		while(!validaString(String.valueOf(senha))){
			System.out.println("\n \t <Digite novamente!>");
			System.out.print(mensagem);
			senha = input.readPassword();
		}
		
		return String.valueOf(senha);
	}
	/**
	 * Valida uma entrada em string recebida
	 * @author Guilherme Santos
	 * @param entrada
	 * @return
	 */
	public static boolean validaString(String entrada) throws Exception{
		
		scanner = new Scanner( System.in );
		
		if ( entrada.trim().isEmpty() ){
			System.out.println("\n \t <Voce deve inserir alguma entrada!>");
			return false;
		}
		
		verificaSeCancelou(entrada);
		return true;
	}
	/**
	 * @param mensagem
	 * @param input
	 * @return int
	 */
	private static int retornaInteiroCorreto(String prompt) throws Exception{
		
		System.out.print(prompt);
		String input = scanner.nextLine();
		
		while(!validaInteiro(input)){
			System.out.println("\n \t <Digite novamente!>");
			System.out.print(prompt);
			input = scanner.nextLine();
		}
		try{
			return Integer.parseInt(input);
		}catch(Exception e){
			System.out.println("\n \t <Opcao invalida!>");
			return retornaInteiroCorreto(prompt);
		}
	}
	
	private static double retornaRealCorreto(String prompt) throws Exception{
		
		System.out.print(prompt);
		String input = scanner.nextLine();
		
		while(!validaReal(input)){
			System.out.println("\n \t <Digite novamente!>");
			System.out.print(prompt);
			input = scanner.nextLine();
		}
		try{
			return Double.parseDouble(input);
		}catch(Exception e){
			System.out.println("\n \t <Opcao invalida!>");
			return retornaRealCorreto(prompt);
		}
	}
	
	/**
	 * @author Pedro Rawan Meireles Limeira
	 * Adiciona na objetos numa determinada List
	 * @param Object - aSerAdicionado
	 * @throws Exception se o objeto for nulo
	 */
	@SuppressWarnings("unchecked")
	public static void adicionaObjetoNaLista(List lista, Object aSerAdicionado) throws Exception{
		
		if(aSerAdicionado == null){
			throw new Exception("\n \t <Elemento nao pode ser adicionado!>");
		}
				
		Iterator iterador = lista.iterator();
		boolean existe=false;
				
		while(iterador.hasNext()){
			if(iterador.next().equals(aSerAdicionado)){
				existe = true;
			}
		}
				
		if(existe){
			throw new Exception("\n \t <Elemento ja esta na lista!>");
		}
		lista.add(aSerAdicionado);
	}
	
	/**
	 * Remove um objeto de uma lista passada como parametro
	 * @param lista - List
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static void excluirObjetoNaLista(List lista) throws Exception{
		
		if ( !lista.isEmpty() ){
			
			System.out.println("\t\t==========================");
			System.out.println("\t\t Excluindo "+lista.get(0).getClass().getSimpleName());
			System.out.println("\t\t==========================");
			
			int escolhida = escolherOpcao(Mensagem.MENSAGEM_SELECAO+listarObjetosNaLista(lista)+"\n["+(lista.size()+1)+"]\nVOLTAR", lista.size()+1);
			if ( escolhida == lista.size()+1 ){
				throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
			}
			else{
				lista.remove(escolhida -1);				
			}
		}
		else {
			System.out.println(listarObjetosNaLista(lista));
		}
	}
	
	/**
	 * Lista os objetos a partir de uma lista utilizando o toString dos objetos da lista
	 * @param lista - List
	 * @return String
	 */
	@SuppressWarnings("unchecked")
	public static String listarObjetosNaLista(List lista) throws Exception{
		
		String retorno="";
		
		if ( lista.isEmpty() ){
			throw new Exception("\n \t <Nao ha elementos desse tipo cadastrados!>\n");
		}
		
		Iterator iterador = lista.iterator();
		int cont=1;
		
		while(iterador.hasNext()){
			retorno+=" \t ["+cont+"]\n"+iterador.next().toString()+"\n";
			cont++;
		}
		
		return retorno;
	}

	
	public static String listarObjetosNoArray(Object[] array){
		
		String stringDeObjetosDoArray = "\n \t Selecione uma das opcoes abaixo: \n";
		
		int quebraDeLinha = 3;
		if ( array[0].getClass().getSimpleName().equals("UF") ){
			quebraDeLinha = 5;
		}
		else if ( array[0].getClass().getSimpleName().equals("Estado") ){
			quebraDeLinha = 2;
		}
		
		for(int i = 0; i < array.length; i++) {
			if ((i + 1) % quebraDeLinha == 0) {
				stringDeObjetosDoArray += "\t [" + (i + 1) + "]" + array[i] + "\n\n";
				
			} else {			
				stringDeObjetosDoArray += "\t [" + (i + 1) + "]" + array[i];
			}
		}
		
		return stringDeObjetosDoArray;
	}
	
	public static Endereco cadastraEndereco() throws Exception {
		
		Endereco novo = new Endereco();
		
		UF[] unidadesDaFederacao = UF.values();
		TipoDeLogradouro[] tiposDeLogradouro = TipoDeLogradouro.values();
		
		System.out.println("\n \t --- Endereco ---");
		UF unidadeDaFederacaoEscolhida = unidadesDaFederacao[escolherOpcao("\n \t -- Unidade da Federacao --\n" + listarObjetosNoArray(unidadesDaFederacao) , unidadesDaFederacao.length) - 1];
		novo.setEstado(unidadeDaFederacaoEscolhida);

		while ( true ){
			// Pede cidade
			String cidade = retornaStringCorreto(Mensagem.FORMULARIO_CIDADE);
			try{
				novo.setCidade(cidade);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		while ( true ){
			// Pede bairro
			String bairro = retornaStringCorreto(Mensagem.FORMULARIO_BAIRRO);
			try{
				novo.setBairro(bairro);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		// Pede Tipo de Logradouro - Itera sobre o array de constantes de TipoDeLogradouro e retorna a constante escolhida pelo usuario
		TipoDeLogradouro tipoDeLogradouroEscolhido = tiposDeLogradouro[escolherOpcao("\n \t -- Tipo de Logradouro --\n" + listarObjetosNoArray(tiposDeLogradouro) , tiposDeLogradouro.length) - 1];
		novo.setTipoDeLogradouro(tipoDeLogradouroEscolhido);
		
		while ( true ){
			// Pede Logradouro
			String logradouro = retornaStringCorreto(Mensagem.FORMULARIO_NOME_DO_LOGRADOURO + tipoDeLogradouroEscolhido + ": ");
			try{
				novo.setLogradouro(logradouro);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while ( true ){
			// Pede Numero
			int numero = retornaInteiroCorreto(Mensagem.FORMULARIO_NUMERO);
			try{
				novo.setNumero(numero);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while ( true ){
			// Pede CEP
			String cep = retornaStringCorreto(Mensagem.FORMULARIO_CEP);
			try{
				novo.setCep(cep);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while ( true ){
			// Pede Observacao
			String observacao = retornaStringCorreto(Mensagem.FORMULARIO_OBSERVACAO);
			try{
				novo.setObs(observacao);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		return novo;
	}
	
	/**
	 * @param entrada - String
	 * @return boolean
	 */
	public static boolean validaInteiro(String entrada) throws Exception{
		
		scanner = new Scanner( System.in );
		
		if ( entrada.trim().isEmpty() ){
			System.out.println("\n \t <Voce deve inserir alguma entrada!>");
			return false;
		}
		
		verificaSeCancelou(entrada);
		
		for ( int i=0; i<entrada.length(); i++ ){
			if ( !Character.isDigit(entrada.charAt(i)) ){
				return false;
			}
		}
		
		return true;
	}

	public static boolean validaReal(String entrada) throws Exception{
        
        scanner = new Scanner( System.in );
        
        if ( entrada.trim().isEmpty() ){
                System.out.println("\n \t <Voce deve inserir alguma entrada!>");
                return false;
        }
        
        verificaSeCancelou(entrada);
        
        Pattern pReal = Pattern.compile("[0-9]+([.])?[0-9]{1,2}");
        
        Matcher mReal = pReal.matcher(entrada);
        
        return mReal.matches();
	}
	
	public static void efetuaDevolucao() throws Exception{
		
		if ( registrosDeLocacaoLista.isEmpty() ){
			throw new Exception("\n \t <Nao ha registros de locacao, logo nao ha como efetuar devolucoes!>");
		}

		System.out.println("\t\t=======================");
		System.out.println("\t\t Efetuando uma Devolucao");
		System.out.println("\t\t=======================");
		
		
		int escolhida = escolherOpcao("\n \t Escolha um desses registros de locacao cadastrados: \n"+(listarObjetosNaLista(registrosDeLocacaoLista))+"\n["+(registrosDeLocacaoLista.size()+1)+"]CANCELAR", registrosDeLocacaoLista.size()+1);
		
		if ( escolhida == registrosDeLocacaoLista.size()+1 ){
			throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
		}
		
		RegistroDeLocacao registro = registrosDeLocacaoLista.get(escolhida-1);
		
		double multaTotal = 0;
		double multasAPagar;

		if (registro.getPlanoDeLocacao().getTipoDeVeiculo() == TipoDeVeiculo.AUTOMOVEL) {
			for (Veiculo veiculo : automoveisLista) {
				for (String codigoVeiculo : registro
						.getCodigosDeVeiculosLocados()) {
					if ((veiculo.getRenavam().replace("-", ""))
							.equals(codigoVeiculo.replace("-", ""))) {

						multasAPagar = 0;

						System.out.println("\n \t Devolvendo o veiculo: \n"
								+ veiculo);

						Estado[] opcoesEstados = { Estado.ARRANHADO,
								Estado.COM_ACESSORIO_DANIFICADO,
								Estado.AMASSADO_LEVE, Estado.AMASSADO_PESADO,
								Estado.ROUBADO };

						int escolhido = escolherOpcao(
								"\n \t Qual a situacao do veiculo?\n"
										+ listarObjetosNoArray(opcoesEstados)
										+ "\n\n \t ["
										+ (opcoesEstados.length + 1)
										+ "]SEM DANOS\n",
								opcoesEstados.length + 1);
						if (escolhido == opcoesEstados.length + 1) {
							veiculo.setEstado(Estado.DISPONIVEL);
						} else {
							veiculo.setEstado(opcoesEstados[escolhido - 1]);
						}

						if (registro.getFormaDePagamento() == FormaDePagamento.DIARIAS) {
							int diasDeAtraso = Data
									.getDiferencaDeDiasEntreDatas(registro
											.getDataDevolucao(), new Data());

							if (diasDeAtraso > 0) {
								multasAPagar += (diasDeAtraso * registro
										.getPlanoDeLocacao()
										.getPrecoBaseDaDiaria())
										+ ((0.05) * diasDeAtraso * registro
												.getPlanoDeLocacao()
												.getPrecoBaseDaDiaria());
								System.out
										.printf(
												"\n \t Multa por dias atrasados: R$ %.2f\n",
												multasAPagar);
							}

						} else if (registro.getFormaDePagamento() == FormaDePagamento.QUILOMETRAGEM) {

							int quilometrosRodados;

							while (true) {
								quilometrosRodados = retornaInteiroCorreto("\n \t Quantos quilometros foram rodados pelo veiculo? ");
								if (quilometrosRodados > 0) {
									break;
								}
								System.out
										.println("\n \t <Valor para os quilometros rodados invalido!>");
							}
							int quilometrosExcedentes = quilometrosRodados
									- registro.getQuilometragemDeclarada();

							if (quilometrosExcedentes > 0) {
								multasAPagar += registro.getPlanoDeLocacao()
										.getPrecoBaseDaDiaria() * (0.1);
								System.out
										.printf(
												"\n \t Multa por quilometros excedentes: R$ %.2f\n",
												multasAPagar);
							}
						}

						int multa = veiculo.getEstado().getValorDeMulta();

						if (multa > 0) {
							System.out.printf("\n \t Multa - %s: R$ %d\n",
									veiculo.getEstado().toString()
											.toLowerCase(), multa);

							if (registro.getPlanoDeLocacao().getSeguro().cobre(
									veiculo.getEstado())) {
								System.out.println("\n \t Seguro "
										+ registro.getPlanoDeLocacao()
												.getSeguro() + " cobre "
										+ veiculo.getEstado() + "!");
								System.out
										.printf(
												"\n \t Desconto na multa de R$ %.2f!\n",
												multa
														* (registro
																.getPlanoDeLocacao()
																.getSeguro()
																.getPorcentagem()));
								multa -= multa
										* (registro.getPlanoDeLocacao()
												.getSeguro().getPorcentagem());
							} else {
								System.out.println("\n \t <Seguro "
										+ registro.getPlanoDeLocacao()
												.getSeguro() + " nao cobre "
										+ veiculo.getEstado() + "!>");
							}

							multasAPagar += multa;

						}

						veiculo.setEstado(Estado.DISPONIVEL);

						for (Integer nivelDeTanque : registro.getInfoVeiculos()
								.keySet()) {
							for (String codigo : registro.getInfoVeiculos()
									.get(nivelDeTanque)) {
								if (codigo.equals(veiculo.getRenavam())) {
									int combustivelFaltando = nivelDeTanque
											- retornaInteiroCorreto("\n \t Informe o nivel do tanque: ");
									if (combustivelFaltando > 0) {
										double multaPeloCombustivel = (combustivelFaltando)
												* (veiculo
														.getTipoDeCombustivel()
														.getPrecoPorUnidade())
												* Constantes.LITROS_POR_PORCENTAGEM_DO_TANQUE;
										multasAPagar += multaPeloCombustivel;
										System.out
												.println("\n \t Ha diferenca no nivel de tanque em relacao ao momento da locacao!");
										System.out
												.printf(
														"\n \t Diferenca de %s!\n\n \t Taxa de ressarcimento no combustivel de R$ %.2f\n",
														combustivelFaltando
																+ "%",
														multaPeloCombustivel);
									}
								}
							}
						}

						System.out
								.printf(
										"\n \t Multa total que deve ser paga por este veiculo: R$ %.2f\n",
										multasAPagar);
						multaTotal += multasAPagar;

					}
				}
			}
		} else if (registro.getPlanoDeLocacao().getTipoDeVeiculo() == TipoDeVeiculo.MOTOCICLETA) {
			for (Veiculo veiculo : motocicletasLista) {
				for (String codigoVeiculo : registro
						.getCodigosDeVeiculosLocados()) {
					if ((veiculo.getRenavam().replace("-", ""))
							.equals(codigoVeiculo.replace("-", ""))) {

						multasAPagar = 0;

						System.out.println("\n \t Devolvendo o veiculo: \n"
								+ veiculo);

						Estado[] opcoesEstados = { Estado.ARRANHADO,
								Estado.COM_ACESSORIO_DANIFICADO,
								Estado.AMASSADO_LEVE, Estado.AMASSADO_PESADO,
								Estado.ROUBADO };

						int escolhido = escolherOpcao(
								"\n \t Qual a situacao do veiculo?\n"
										+ listarObjetosNoArray(opcoesEstados)
										+ "\n\n \t ["
										+ (opcoesEstados.length + 1)
										+ "]SEM DANOS\n",
								opcoesEstados.length + 1);
						if (escolhido == opcoesEstados.length + 1) {
							veiculo.setEstado(Estado.DISPONIVEL);
						} else {
							veiculo.setEstado(opcoesEstados[escolhido - 1]);
						}

						if (registro.getFormaDePagamento() == FormaDePagamento.DIARIAS) {
							int diasDeAtraso = Data
									.getDiferencaDeDiasEntreDatas(registro
											.getDataDevolucao(), new Data());

							if (diasDeAtraso > 0) {
								multasAPagar += (diasDeAtraso * registro
										.getPlanoDeLocacao()
										.getPrecoBaseDaDiaria())
										+ ((0.05) * diasDeAtraso * registro
												.getPlanoDeLocacao()
												.getPrecoBaseDaDiaria());
								System.out
										.printf(
												"\n \t Multa por dias atrasados: R$ %.2f\n",
												multasAPagar);
							}

						} else if (registro.getFormaDePagamento() == FormaDePagamento.QUILOMETRAGEM) {

							int quilometrosRodados;

							while (true) {
								quilometrosRodados = retornaInteiroCorreto("\n \t Quantos quilometros foram rodados pelo veiculo? ");
								if (quilometrosRodados > 0) {
									break;
								}
								System.out
										.println("\n \t <Valor para os quilometros rodados invalido!>");
							}
							int quilometrosExcedentes = quilometrosRodados
									- registro.getQuilometragemDeclarada();

							if (quilometrosExcedentes > 0) {
								multasAPagar += registro.getPlanoDeLocacao()
										.getPrecoBaseDaDiaria() * (0.1);
								System.out
										.printf(
												"\n \t Multa por quilometros excedentes: R$ %.2f\n",
												multasAPagar);
							}
						}

						int multa = veiculo.getEstado().getValorDeMulta();

						if (multa > 0) {
							System.out.printf("\n \t Multa - %s: R$ %d\n",
									veiculo.getEstado().toString()
											.toLowerCase(), multa);

							if (registro.getPlanoDeLocacao().getSeguro().cobre(
									veiculo.getEstado())) {
								System.out.println("\n \t Seguro "
										+ registro.getPlanoDeLocacao()
												.getSeguro() + " cobre "
										+ veiculo.getEstado() + "!");
								System.out
										.printf(
												"\n \t Desconto na multa de R$ %.2f!\n",
												multa
														* (registro
																.getPlanoDeLocacao()
																.getSeguro()
																.getPorcentagem()));
								multa -= multa
										* (registro.getPlanoDeLocacao()
												.getSeguro().getPorcentagem());
							} else {
								System.out.println("\n \t <Seguro "
										+ registro.getPlanoDeLocacao()
												.getSeguro() + " nao cobre "
										+ veiculo.getEstado() + "!>");
							}

							multasAPagar += multa;

						}

						veiculo.setEstado(Estado.DISPONIVEL);

						for (Integer nivelDeTanque : registro.getInfoVeiculos()
								.keySet()) {
							for (String codigo : registro.getInfoVeiculos()
									.get(nivelDeTanque)) {
								if (codigo.equals(veiculo.getRenavam())) {
									int combustivelFaltando = nivelDeTanque
											- retornaInteiroCorreto("\n \t Informe o nivel do tanque: ");
									if (combustivelFaltando > 0) {
										double multaPeloCombustivel = (combustivelFaltando)
												* (veiculo
														.getTipoDeCombustivel()
														.getPrecoPorUnidade())
												* Constantes.LITROS_POR_PORCENTAGEM_DO_TANQUE;
										multasAPagar += multaPeloCombustivel;
										System.out
												.println("\n \t Ha diferenca no nivel de tanque em relacao ao momento da locacao!");
										System.out
												.printf(
														"\n \t Diferenca de %s!\n\n \t Taxa de ressarcimento no combustivel de R$ %.2f\n",
														combustivelFaltando
																+ "%",
														multaPeloCombustivel);
									}
								}
							}
						}

						System.out
								.printf(
										"\n \t Multa total que deve ser paga por este veiculo: R$ %.2f\n",
										multasAPagar);
						multaTotal += multasAPagar;

					}
				}
			}
		}

		System.out.printf("\n\n \t Multa TOTAL que o cliente deve pagar: R$ %.2f",multaTotal);
		registro.setMultaTotal(multaTotal);
		registrosDeLocacaoLista.remove(registro);
		registrosDeDevolucaoLista.add(registro);
		geradorDeLog.escreveLog("Devolucao "+registro.getCodigoDoRegistro()+" cliente: "+registro.getCodigoDoCliente()+
								" multa R$: "+registro.getMultaTotal()+" forma: "+registro.getFormaDePagamento()+
								" plano: "+registro.getPlanoDeLocacao().getCodigo());
		
	}
	
	public static void efetuaLocacao() throws Exception{

		List<Veiculo> temp = new ArrayList<Veiculo>();
		temp.addAll(automoveisLista);
		temp.addAll(motocicletasLista);
		if ( temp.isEmpty() ){
			throw new Exception("\n \t <Nao ha veiculos na Agencia!>\n \t <Novos veiculos precisam ser adquiridos pela Agencia!>");
		}
		if ( planosLista.isEmpty() ){
			throw new Exception("\n \t <Nao ha planos de locacao cadastrados!>\n \t <Cadastre um plano de locacao!>");
		}
		
		System.out.println("\t\t=======================");
		System.out.println("\t\t Efetuando uma Locacao");
		System.out.println("\t\t=======================");
		
		RegistroDeLocacao locacao = new RegistroDeLocacao();
				
		
		int tipoDeCliente = 0;
		while (true){
			tipoDeCliente = escolherOpcao("\n \t Qual o tipo de cliente:\n \t [1]Pessoa Fisica\t[2]Pessoa Juridica\t[3]CANCELAR",3);
			if ( tipoDeCliente == CLIENTE_FISICO ){
				if ( clientesFisicosLista.isEmpty() ){
					throw new Exception("\n \t <Nao ha clientes pessoa fisica cadastrados!>");
				}
				int escolhido = escolherOpcao("\n \t Escolha um desses clientes pessoa fisica cadastrados: \n"+listarObjetosNaLista(clientesFisicosLista)+"\n \t ["+(clientesFisicosLista.size()+1)+"]CANCELAR\n", clientesFisicosLista.size()+1);
				if ( escolhido == clientesFisicosLista.size()+1 ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				ClienteFisico cliente = clientesFisicosLista.get(escolhido-1);
				locacao.setCodigoDoCliente(cliente.getCPF());
			}
			else if ( tipoDeCliente == CLIENTE_JURIDICO ){
				if ( clientesJuridicosLista.isEmpty() ){
					throw new Exception("\n \t <Nao ha clientes pessoa juridica cadastrados!>");
				}
				int escolhido = escolherOpcao("\n \t Escolha um desses clientes pessoa juridica cadastrados: \n"+listarObjetosNaLista(clientesJuridicosLista)+"\n \t ["+(clientesJuridicosLista.size()+1)+"]CANCELAR\n", clientesJuridicosLista.size()+1);
				if ( escolhido == clientesJuridicosLista.size()+1 ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				ClienteJuridico cliente = clientesJuridicosLista.get(escolhido-1);
				locacao.setCodigoDoCliente(cliente.getCNPJ());
			}
			else{
				throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
			}
			boolean clienteValido = true;
			for ( RegistroDeLocacao reg : registrosDeLocacaoLista ){
				if ( locacao.getCodigoDoCliente().equals(reg.getCodigoDoCliente()) ){
					clienteValido = false;
					System.out.println("\n \t <Esse cliente esta com locacoes pendentes!>\n \t <Escolha outro cliente!>");
				}
			}
			if ( clienteValido ){
				break;
			}
		}
		
		ArrayList<Veiculo> veiculosQueOPlanoOferece;
		Iterator<Veiculo> iterador;
		PlanoDeLocacao planoEscolhido;
		while (true){

			int escolhida = escolherOpcao("\n \t Escolha um desses planos de locacao: \n"+listarObjetosNaLista(planosLista)+" \t ["+(planosLista.size()+1)+"]CANCELAR\n", planosLista.size()+1);
			if ( escolhida == planosLista.size()+1 ){
				throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
			}
			
			planoEscolhido = planosLista.get(escolhida-1);
			locacao.setPlanoDeLocacao(planoEscolhido);
			
			veiculosQueOPlanoOferece = new ArrayList<Veiculo>();
			
			List<Veiculo> tmp = new ArrayList<Veiculo>();
			tmp.addAll(automoveisLista);
			tmp.addAll(motocicletasLista);
			iterador = tmp.iterator();
			while ( iterador.hasNext() ){
				Veiculo veiculo = iterador.next();
				if ( veiculo.getEstado() == Estado.ALUGADO ){
					continue;
				}
				if ( planoEscolhido.getTipoDeVeiculo() == TipoDeVeiculo.AUTOMOVEL ){
					if ( veiculo instanceof Automovel ){
						boolean marcaOferecida = false;
						boolean modeloOferecido = false;

						marcaOferecida = planoEscolhido.getMarcaXModelos().containsKey(veiculo.getMarca());
						
						if ( marcaOferecida ){
							modeloOferecido = planoEscolhido.getMarcaXModelos().get(veiculo.getMarca()).contains(veiculo.getModelo());
						}
						if ( marcaOferecida && modeloOferecido ){
							HashSet<Acessorio> acessoriosQueOPlanoOferece = new HashSet<Acessorio>();
							for ( int i=0; i<planoEscolhido.getAcessorios().length; i++ ){
								if ( planoEscolhido.getAcessorios()[i] != null ){
									acessoriosQueOPlanoOferece.add(planoEscolhido.getAcessorios()[i]);
								}
							}
							if ( veiculo.getAcessorios().containsAll(acessoriosQueOPlanoOferece) ){
								if ( veiculo.getPotencia() == planoEscolhido.getPotencia() ){
									veiculosQueOPlanoOferece.add(veiculo);
								}
							}
						}
					}
				}
				else if ( planoEscolhido.getTipoDeVeiculo() == TipoDeVeiculo.MOTOCICLETA ){
					if ( veiculo instanceof Motocicleta ){
						boolean marcaOferecida = false;
						boolean modeloOferecido = false;

						marcaOferecida = planoEscolhido.getMarcaXModelos().containsKey(veiculo.getMarca());
						
						if ( marcaOferecida ){
							modeloOferecido = planoEscolhido.getMarcaXModelos().get(veiculo.getMarca()).contains(veiculo.getModelo());
						}
						if ( marcaOferecida && modeloOferecido ){
							HashSet<Acessorio> acessoriosQueOPlanoOferece = new HashSet<Acessorio>();
							for ( int i=0; i<planoEscolhido.getAcessorios().length; i++ ){
								if ( planoEscolhido.getAcessorios()[i] != null ){
									acessoriosQueOPlanoOferece.add(planoEscolhido.getAcessorios()[i]);
								}
							}
							if ( veiculo.getAcessorios().containsAll(acessoriosQueOPlanoOferece) ){
								if ( veiculo.getPotencia() == planoEscolhido.getPotencia() ){
									veiculosQueOPlanoOferece.add(veiculo);
								}
							}
						}
					}
				}
			}
			try{
				if ( veiculosQueOPlanoOferece.isEmpty() ){
					throw new Exception("\n \t <A Agencia nao dispoe no momento de nenhum veiculo com as caracteristicas que o plano oferece!>");
				}
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		
		HashMap<Integer, HashSet<String>> veiculosAlugados = new HashMap<Integer, HashSet<String>>();
		
		while (true){
			iterador = veiculosQueOPlanoOferece.iterator();
			int contador = 0;
			String veiculosListados = "\n \t Esse plano oferece este(s) veiculo(s).\n \t Escolha um dele(s): \n";
			while ( iterador.hasNext() ){
				veiculosListados += " \t ["+(++contador)+"]\n"+iterador.next().toString();
			}
			veiculosListados += "\n \t ["+(contador+1)+"]NAO LOCAR MAIS\n";

			int escolhido = escolherOpcao(veiculosListados, contador+1);
			if ( escolhido == contador+1 ){
				if ( !veiculosAlugados.isEmpty() ){
					break;					
				}
				System.out.println("\n \t <Voce deve locar pelo menos um veiculo!>");
				continue;
			}
			else{
				Veiculo[] veiculosArray = new Veiculo[veiculosQueOPlanoOferece.size()];
				Iterator<Veiculo> iterador2 = veiculosQueOPlanoOferece.iterator();
				contador = 0;
				while ( iterador2.hasNext() ){
					veiculosArray[contador++] = iterador2.next();
				}
				if ( !veiculosAlugados.containsKey(veiculosArray[escolhido-1].getNivelDoTanque()) ){
					veiculosAlugados.put(veiculosArray[escolhido-1].getNivelDoTanque(), new HashSet<String>());
				}
				veiculosAlugados.get(veiculosArray[escolhido-1].getNivelDoTanque()).add(veiculosArray[escolhido-1].getRenavam());
				veiculosArray[escolhido-1].setEstado(Estado.ALUGADO);
				veiculosQueOPlanoOferece.remove(veiculosArray[escolhido-1]);
			}
			if ( tipoDeCliente == CLIENTE_FISICO ){
	
				if ( veiculosAlugados.values().size() < Constantes.QTDE_VEICULOS_MAX_PESSOA_FISICA ){
					int opcao = escolherOpcao("\n \t Voce ainda pode alugar mais carros.\n \t Eh isso que deseja?\n \t[1]Sim\t[2]Nao\n",2);
					if ( opcao == NAO){
						break;
					}
					if ( veiculosQueOPlanoOferece.isEmpty() ){
						System.out.println("\n \t <Desculpe, nao ha mais veiculos que esse plano ofereca!>");
						break;
					}
				}
				else{
					System.out.println("\n \t <Limite de veiculos para um cliente pessoa fisica atingido.>");
					break;
				}
			}
			else if ( tipoDeCliente == CLIENTE_JURIDICO ){
				System.out.println(veiculosAlugados.values().size());
				if ( veiculosAlugados.values().size() < Constantes.QTDE_VEICULOS_MAX_PESSOA_JURIDICA ){
					int opcao = escolherOpcao("\n \t Voce ainda pode alugar mais carros.\n \t Eh isso que deseja?\n \t[1]Sim\t[2]Nao\n",2);
					if ( opcao == NAO){
						break;
					}
					if ( veiculosQueOPlanoOferece.isEmpty() ){
						System.out.println("\n \t <Desculpe, nao ha mais veiculos que esse plano ofereca!>");
						break;
					}
				}
				else{
					System.out.println("\n \t <Limite de veiculos para um cliente pessoa juridica atingido.>");
					break;
				}
			}
		}
		locacao.setInfoVeiculos(veiculosAlugados);
		
		extratoDaLocacao = new Extrato();
		extratoDaLocacao.setCodigoDoCliente(locacao.getCodigoDoCliente());
		extratoDaLocacao.setCodigosDosVeiculos(locacao.getCodigosDeVeiculosLocados());
		extratoDaLocacao.setCodigoDoRegistroDeLocacao(locacao.getCodigoDoRegistro());
		
		int formaDePagamento = escolherOpcao("\n \t Qual a forma de pagamento?\n \t[1]Diarias\t[2]Quilometragem", 2);
		Data dataDevolucao = null;
		double precoDaLocacao = 0;
		double precoBase = 0;
		int qtdeDiarias = 0;
		
		if ( formaDePagamento == DIARIAS ){
			locacao.setFormaDePagamento(FormaDePagamento.DIARIAS);
			extratoDaLocacao.setFormaDePagamento(FormaDePagamento.DIARIAS);
			while (true){
				try{
					System.out.println("\n \t---Informe a data de devolucao do(s) veiculo(s)---");			
					int dia = retornaInteiroCorreto(Mensagem.FORMULARIO_DIA);
					int mes = Mes.values()[escolherOpcao(Mensagem.FORMULARIO_MES + listarObjetosNoArray(Mes.values()), Mes.values().length) - 1].getNumero();
					int ano = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
					dataDevolucao = new Data(dia,mes,ano);
					locacao.setDataEntrega(new Data());
					locacao.setDataDevolucao(dataDevolucao);
					extratoDaLocacao.setDataDeLocacao(locacao.getDataEntrega());
					extratoDaLocacao.setDataDeDevolucao(locacao.getDataDevolucao());
					qtdeDiarias = Data.getDiferencaDeDiasEntreDatas(new Data(), dataDevolucao)+1;
					System.out.println("\n \t Quantidade de diarias a serem pagas por cada veiculo: "+qtdeDiarias);
					extratoDaLocacao.setQtdeDiariasASeremPagas(qtdeDiarias);
					break;
				}
				catch(Exception e){
					if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
						throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
					}
					System.out.println(e.getMessage());
				}
			}
			precoBase = planoEscolhido.getPrecoBaseDaDiaria();
			extratoDaLocacao.setPrecoDaDiaria(precoBase);
			extratoDaLocacao.addInfo(String.format("Preco da diaria do plano: R$ %.2f",extratoDaLocacao.getPrecoDaDiaria()));
			for ( int i=1; i<qtdeDiarias; i++ ){
				if ( i%5 == 0 && i<Constantes.QTDE_MAX_DIAS_COM_DESCONTO ){
					precoBase -= precoBase*(Constantes.PORCENTAGEM_DESCONTO_NAS_DIARIAS);
				}
			}
			extratoDaLocacao.addInfo("Quantidade de diarias a serem pagas por cada veiculo: " + extratoDaLocacao.getQtdeDiariasASeremPagas());
			extratoDaLocacao.addInfo(String.format("Desconto de R$ %.2f",(extratoDaLocacao.getPrecoDaDiaria()-precoBase)));
			extratoDaLocacao.setPrecoDaDiaria(precoBase);
			extratoDaLocacao.addInfo(String.format("Preco final da diaria: R$ %.2f",extratoDaLocacao.getPrecoDaDiaria()));
						
			for ( int i=0; i<qtdeDiarias; i++ ){
				precoDaLocacao += precoBase;
			}

			precoDaLocacao *= locacao.getCodigosDeVeiculosLocados().size();
			
			extratoDaLocacao.setPrecoDaLocacao(precoDaLocacao);
			extratoDaLocacao.addInfo(String.format("Preco da locacao: R$ %.2f",extratoDaLocacao.getPrecoDaLocacao()));
			
		}
		else if ( formaDePagamento == QUILOMETRAGEM ){
			locacao.setFormaDePagamento(FormaDePagamento.QUILOMETRAGEM);
			extratoDaLocacao.setFormaDePagamento(locacao.getFormaDePagamento());
			locacao.setDataEntrega(new Data());
			extratoDaLocacao.setDataDeLocacao(locacao.getDataEntrega());
			String quilometragens = "\n \t Escolha a quilometragem desejada: \n";
			for ( int i=0; i<Constantes.QUILOMETRAGENS_ATE_X.length; i++ ){
				quilometragens += " \t ["+(i+1)+"]Ate "+Constantes.QUILOMETRAGENS_ATE_X[i]+"km\n";
			}
			int quilometragemDesejada = Constantes.QUILOMETRAGENS_ATE_X[escolherOpcao(quilometragens, Constantes.QUILOMETRAGENS_ATE_X.length)-1];
			locacao.setQuilometragemDeclarada(quilometragemDesejada);
			extratoDaLocacao.setQuilometragem(quilometragemDesejada);
			
			extratoDaLocacao.setPrecoDaDiaria(planoEscolhido.getPrecoBaseDaDiaria());
			
			extratoDaLocacao.addInfo(String.format("Preco da diaria do plano: R$ %.2f",extratoDaLocacao.getPrecoDaDiaria()));
			precoBase = planoEscolhido.getPrecoBaseDaDiaria()*(Constantes.PORCENTAGEM_DESCONTO_NA_DIARIA_PRECO_POR_QUILOMETRO);
			extratoDaLocacao.setPrecoPorQuilometro(precoBase);
			extratoDaLocacao.addInfo(String.format("Preco por quilometro rodado de cada veiculo: R$ %.2f",extratoDaLocacao.getPrecoPorQuilometro()));

			
			for ( int i=0; i<locacao.getQuilometragemDeclarada(); i++ ){
				precoDaLocacao+= precoBase;
			}

			precoDaLocacao *= locacao.getCodigosDeVeiculosLocados().size();
			
			extratoDaLocacao.setPrecoDaLocacao(precoDaLocacao);
			extratoDaLocacao.addInfo(String.format("Preco da locacao: R$ %.2f",extratoDaLocacao.getPrecoDaLocacao()));
		}
		
		if ( planoEscolhido.getSeguro() != Seguro.SEM_SEGURO ){
			extratoDaLocacao.setPrecoDoSeguro(planoEscolhido.getSeguro().getValorDeMultaTotal()*(Constantes.PORCENTAGEM_DESCONTO_MULTA_PRECO_POR_SEGURO));

			precoDaLocacao += extratoDaLocacao.getPrecoDoSeguro();
					
			extratoDaLocacao.addInfo(String.format("Preco do seguro: R$ %.2f",extratoDaLocacao.getPrecoDoSeguro()));
		}
		else{
			extratoDaLocacao.addInfo("Nao contem seguro.");
			extratoDaLocacao.setPrecoDoSeguro(0);
		}
		
		@SuppressWarnings("unused")
		int opcao = escolherOpcao(String.format("\n \t ---A locacao custa R$ %.2f!\n \t [1]OK",precoDaLocacao), 1);
		locacao.setPrecoDaLocacao(precoDaLocacao);
		extratoDaLocacao.setPrecoTotal(locacao.getPrecoDaLocacao());
		extratoDaLocacao.addInfo(String.format("PRECO TOTAL DA LOCACAO: R$ %.2f",extratoDaLocacao.getPrecoTotal()));

		registrosDeLocacaoLista.add(locacao);
		
		geradorDeLog.escreveLog("Locacao numero "+locacao.getCodigoDoRegistro()+" realizada"+" cliente: "+
								locacao.getCodigoDoCliente()+" veiculos: "+locacao.getCodigosDeVeiculosLocados()+
								"data da devolucao: "+locacao.getDataDevolucao());
		
		GeradorDeExtrato gerador = new GeradorDeExtrato(extratoDaLocacao);
		gerador.gerar();
		
	}//Fim do Efetua Locacao
	
	public static void cadastraPlano() throws Exception{
		
		System.out.println("\t\t=======================");
		System.out.println("\t\t Cadastrando Plano");
		System.out.println("\t\t=======================");

		PlanoDeLocacao plano = new PlanoDeLocacao();
		
		TipoDeVeiculo tipoDeVeiculo = TipoDeVeiculo.values()[escolherOpcao(Mensagem.FORMULARIO_TIPO_DE_VEICULO + listarObjetosNoArray(TipoDeVeiculo.values()), 2)-1];
		plano.setTipoDeVeiculo(tipoDeVeiculo);
		
		while (true){
			System.out.println("\n \t --- Inserindo marcas e modelos de veiculos ---");
			int qtdeMarcas = 0;
			qtdeMarcas = retornaInteiroCorreto(Mensagem.FORMULARIO_MARCAS);
			while ( qtdeMarcas < 1 ){
				System.out.println(Mensagem.MENSAGEM_FALTA_DE_MARCAS);
				qtdeMarcas = retornaInteiroCorreto(Mensagem.FORMULARIO_MARCAS);
			}
			
			HashMap<String, HashSet<String>> mapaMarcasModelos = new HashMap<String, HashSet<String>>();
			
			for ( int i=1; i<=qtdeMarcas; i++ ){
				mapaMarcasModelos.put(retornaStringCorreto("\n \t Qual a "+i+"a. marca: "), new HashSet<String>());
			}
			
			for ( String marca : mapaMarcasModelos.keySet() ){
				int qtdeModelos = 0;
				qtdeModelos = retornaInteiroCorreto(
						Mensagem.FORMULARIO_MODELOS + marca+": ");
				while ( qtdeModelos < 1 ){
					System.out.println(Mensagem.MENSAGEM_FALTA_DE_MODELOS + marca+ ">!");
					qtdeModelos = retornaInteiroCorreto(
							Mensagem.FORMULARIO_MODELOS + marca+": ");
				}
				for ( int j=0; j<qtdeModelos; j++ ){
					mapaMarcasModelos.get(marca).add(retornaStringCorreto(
							"\n \t Qual o "+(j+1)+"o. modelo da marca "+marca+": "));
				}
			}
			
			try{
				plano.setMarcasXModelos(mapaMarcasModelos);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			ArrayList<Acessorio> acessorios =new ArrayList<Acessorio>();
			StringBuilder acessorio = new StringBuilder();
			
			int[] indices = new int[Acessorio.values().length];
			int contador = 0;
			
			for(int i=0; i < Acessorio.values().length;i++){
				if ( tipoDeVeiculo == TipoDeVeiculo.AUTOMOVEL ){
					if ( Acessorio.values()[i].getPresenca() <= 0 ){
						indices[contador] = i;
						contador++;
					}
				}
				else if ( tipoDeVeiculo == TipoDeVeiculo.MOTOCICLETA ){
					if ( Acessorio.values()[i].getPresenca() >= 0 ){
						indices[contador] = i;
						contador++;
					}
				}
			}
			
			for ( int i=0; i<indices.length; i++ ){
				if ( i<contador ){
					acessorio.append(" \t ["+(i+1)+"]"+Acessorio.values()[indices[i]].getDescricao()+"\n");				
				}
			}
			acessorio.append(" \t ["+(contador+1)+"]"+"ENCERRA CADASTRO\n");
			
			while(true){
				
				System.out.println(Mensagem.FORMULARIO_ACESSORIOS);
							
				int escolhida = escolherOpcao(acessorio.toString(), contador+1);

				if(escolhida == contador+1){
					break;
				}
				else{
					Acessorio acessor = Acessorio.values()[indices[escolhida - 1]];
					acessorios.add(acessor);
					System.out.println("\n \t Acessorio "+acessor.getDescricao()+" adicionado com sucesso.");
				}
			}
			
			Acessorio[] acessoriosRetorno = new Acessorio[acessorios.size()+(Constantes.QTDE_ACESSORIOS_POR_PLANO-acessorios.size())];
			for ( int i=0; i<(acessorios.size()); i++ ){
				acessoriosRetorno[i] = acessorios.get(i);
			}
			for ( int j=acessorios.size(); j<Constantes.QTDE_ACESSORIOS_POR_PLANO; j++ ){
				acessoriosRetorno[j] = null;
			}

			try{
				plano.setAcessorios(acessoriosRetorno);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		int temSeguro = escolherOpcao(Mensagem.FORMULARIO_EXISTE_SEGURO,2);
		Seguro[] seguros = Seguro.values();
		Seguro seguro = null;
		if ( temSeguro == SIM ){
			seguro = seguros[escolherOpcao("\n \t -- Informe o tipo de seguro --\n" + listarObjetosNoArray(seguros), seguros.length) - 1];
		}
		plano.setSeguro(seguro);
		
		while (true){
			int potencia = retornaInteiroCorreto(Mensagem.FORMULARIO_POTENCIA);
			try{
				plano.setPotencia(potencia);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		while (true){
			int cilindrada = 0;
			if ( tipoDeVeiculo == TipoDeVeiculo.MOTOCICLETA ){
				cilindrada = retornaInteiroCorreto(Mensagem.FORMULARIO_CILINDRADAS);
			}
			else{
				break;
			}
			try{
				plano.setCilindradas(cilindrada);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			double precoBaseDaDiaria = retornaRealCorreto(Mensagem.FORMULARIO_PRECO_BASE_DIARIAS);
			try{
				plano.setPrecoBaseDaDiaria(precoBaseDaDiaria);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		adicionaObjetoNaLista(planosLista, plano);
		geradorDeLog.escreveLog("Plano "+plano.getCodigo()+" cadastrado");

	}
	
	public static void cadastraAutomovel() throws Exception{
		
		String renavam = null, modelo = null, marca = null, placa = null; 
		int ano, potencia, nivelDoTanque;
		Potencia[] tiposDePotencia = Potencia.values();
		Potencia tipoDePotencia;
		Cor cor;
		Cor[] cores = Cor.values();
		Combustivel tipoDeCombustivel;
		Combustivel[] tiposDeCombustivel = Combustivel.values();
		Data dataDeAquisicao = null;
		List<Acessorio> acessorios;
			
		System.out.println("\t\t=======================");
		System.out.println("\t\t Cadastrando Automovel");
		System.out.println("\t\t=======================");

		Veiculo novo = new Automovel();
		
		acessorios = new ArrayList<Acessorio>();

		while ( true ){
			
			while (true){
				//Pede RENAVAM
				renavam = retornaStringCorreto(Mensagem.FORMULARIO_RENAVAM);
				try{
					novo.setRenavam(renavam);
					break;
				}
				catch(Exception e){
					System.out.println(e.getMessage());
				}
			}

			//----Pede Placa-----//
			placa = retornaStringCorreto(Mensagem.FORMULARIO_PLACA);
			try{
				novo.setPlaca(placa);
				List<Veiculo> temp = new ArrayList<Veiculo>();
				temp.addAll(automoveisLista);
				temp.addAll(motocicletasLista);
				validaExistencia(temp, novo, "\n \t <Esse RENAVAM ou placa ja foi cadastrado!>");
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			//Pede Marca
			marca = retornaStringCorreto(Mensagem.FORMULARIO_MARCA);
			try{
				novo.setMarca(marca);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		while (true){
			//Pede Modelo
			modelo = retornaStringCorreto(Mensagem.FORMULARIO_MODELO);
			try{
				novo.setModelo(modelo);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			//----Pede Ano----//
			ano = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
			try{
				novo.setAno(ano);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		//----Pede tipo da potencia----//
		tipoDePotencia = tiposDePotencia[escolherOpcao(Mensagem.FORMULARIO_TIPO_POTENCIA + listarObjetosNoArray(tiposDePotencia), tiposDePotencia.length) - 1];
		novo.setTipoDePotencia(tipoDePotencia);

		while (true){
			//----Pede potencia----//
			potencia = retornaInteiroCorreto(Mensagem.FORMULARIO_POTENCIA);
			try{
				novo.setPotencia(potencia);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		Porta qtdePortas = Porta.values()[escolherOpcao(Mensagem.FORMULARIO_PORTAS + "\n \t [1] 2 portas\t [2] 4 portas\n", Porta.values().length) - 1];
		novo.setPortas(qtdePortas);
		
		while (true){
			//----Pede Acessorios----//
			acessorios =new ArrayList<Acessorio>();
			StringBuilder acessorio = new StringBuilder();
			
			int[] indices = new int[Acessorio.values().length];
			int contador = 0;
			
			for(int i=0; i < Acessorio.values().length;i++){
				if (Acessorio.values()[i].getPresenca() <= 0){
					indices[contador] = i;
					contador++;
				}
			}
			
			for ( int i=0; i<indices.length; i++ ){
				if ( i<contador ){
					acessorio.append(" \t ["+(i+1)+"]"+ Acessorio.values()[indices[i]].getDescricao()+"\n");
				}
			}
			acessorio.append(" \t ["+(contador+1)+"]"+"ENCERRA CADASTRO\n");
			
			while(true){
				
				System.out.println(Mensagem.FORMULARIO_ACESSORIOS);
							
				int escolhida = escolherOpcao(acessorio.toString(), contador+1);

				if(escolhida == contador+1){
					break;
				}
				else{
					Acessorio acessor = Acessorio.values()[indices[escolhida - 1]];
					acessorios.add(acessor);
					System.out.println("\n \t Acessorio "+acessor.getDescricao()+" adicionado com sucesso.");
				}
			}
			try{
				novo.setAcessorios(acessorios);
				break;
			}
			catch (Exception e){
				System.out.println(e.getMessage());
			}
		}

		while (true){
			//----Pede Data de aquisicao----//
			System.out.println(" \t ---Informe a data da aquisicao---");
			int dia = retornaInteiroCorreto(Mensagem.FORMULARIO_DIA);
			int mes = Mes.values()[escolherOpcao(Mensagem.FORMULARIO_MES + listarObjetosNoArray(Mes.values()), Mes.values().length) - 1].getNumero();
			int anoData = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
			try{
				dataDeAquisicao = new Data(dia, mes, anoData);
				novo.setDataDeAquisicao(dataDeAquisicao);
				break;
			}
			catch (Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		//----Pede Cor----//
		cor = cores[escolherOpcao("\n \t -- Informe a cor do veiculo --\n" + listarObjetosNoArray(cores), cores.length) - 1];
		novo.setCor(cor);
		
		//----Pede tipo de combustivel----//
		tipoDeCombustivel = tiposDeCombustivel[escolherOpcao("\n\t-- Informe o tipo de combustivel --\n" + listarObjetosNoArray(tiposDeCombustivel), tiposDeCombustivel.length) - 1];
		novo.setTipoDeCombustivel(tipoDeCombustivel);

		while (true){
			//----Pede nivelDoTanque----//
			nivelDoTanque = retornaInteiroCorreto(Mensagem.FORMULARIO_NIVEL_DO_TANQUE);
			try{
				novo.setNivelDoTanque(nivelDoTanque);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		//----Pede Estado do veiculo----//
		int[] indices = new int[Estado.values().length];
		int contador = 0;
		
		String estado = "";
		for(int i=0; i < Estado.values().length;i++){
			if ( !(Estado.values()[i] == Estado.ALUGADO) ){
				indices[contador] = i;
				contador++;
			}
		}
		
		for ( int i=0; i<indices.length; i++ ){
			if ( i<contador ){
				estado += " \t ["+(i+1)+"]"+ Estado.values()[indices[i]]+"\n";				
			}
		}

		int escolhida = escolherOpcao(Mensagem.FORMULARIO_ESTADOS+estado, contador);
		Estado estadoDoVeiculo = Estado.values()[indices[escolhida - 1]];
		novo.setEstado(estadoDoVeiculo);
		
		//Tenta construir adicionar
		List<Veiculo> temp = new ArrayList<Veiculo>();
		temp.addAll(automoveisLista);
		temp.addAll(motocicletasLista);
		adicionaObjetoNaLista(temp, novo);
		geradorDeLog.escreveLog("Automovel de placa "+novo.getPlaca()+" e RENAVAM "+novo.getRenavam()+" cadastrado");
	}
	
	public static void cadastraMotocicleta() throws Exception{

		String renavam = null, modelo = null, marca = null, placa = null; 
		int ano, potencia, nivelDoTanque;
		Potencia[] tiposDePotencia = Potencia.values();
		Potencia tipoDePotencia;
		Cor cor;
		Cor[] cores = Cor.values();
		Combustivel tipoDeCombustivel;
		Combustivel[] tiposDeCombustivel = Combustivel.values();
		Data dataDeAquisicao = null;
		List<Acessorio> acessorios;
		Freio[] tiposDeFreio = Freio.values();
		Freio tipoDeFreio = null;
		int cilindradas;
		
		System.out.println("\t\t=========================");
		System.out.println("\t\t Cadastrando Motocicleta");
		System.out.println("\t\t=========================");

		Motocicleta novo = new Motocicleta();
		
		acessorios = new ArrayList<Acessorio>();

		while ( true ){
			
			while (true){
				//Pede RENAVAM
				renavam = retornaStringCorreto(Mensagem.FORMULARIO_RENAVAM);
				try{
					novo.setRenavam(renavam);
					break;
				}
				catch(Exception e){
					System.out.println(e.getMessage());
				}
			}

			//----Pede Placa-----//
			placa = retornaStringCorreto(Mensagem.FORMULARIO_PLACA);
			try{
				novo.setPlaca(placa);
				List<Veiculo> temp = new ArrayList<Veiculo>();
				temp.addAll(automoveisLista);
				temp.addAll(motocicletasLista);
				validaExistencia(temp, novo, "\n \t <Esse RENAVAM ou placa ja foi cadastrado!>");
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			//Pede Marca
			marca = retornaStringCorreto(Mensagem.FORMULARIO_MARCA);
			try{
				novo.setMarca(marca);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		while (true){
			//Pede Modelo
			modelo = retornaStringCorreto(Mensagem.FORMULARIO_MODELO);
			try{
				novo.setModelo(modelo);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			//----Pede Ano----//
			ano = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
			try{
				novo.setAno(ano);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		//----Pede tipo da potencia----//
		tipoDePotencia = tiposDePotencia[escolherOpcao(Mensagem.FORMULARIO_TIPO_POTENCIA + listarObjetosNoArray(tiposDePotencia), tiposDePotencia.length) - 1];
		novo.setTipoDePotencia(tipoDePotencia);

		while (true){
			//----Pede potencia----//
			potencia = retornaInteiroCorreto(Mensagem.FORMULARIO_POTENCIA);
			try{
				novo.setPotencia(potencia);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			//----Pede Acessorios----//
			acessorios =new ArrayList<Acessorio>();
			StringBuilder acessorio = new StringBuilder();
			
			int[] indices = new int[Acessorio.values().length];
			int contador = 0;
			
			for(int i=0; i < Acessorio.values().length;i++){
				if (Acessorio.values()[i].getPresenca() >= 0){
					indices[contador] = i;
					contador++;
				}
			}
			
			for ( int i=0; i<indices.length; i++ ){
				if ( i<contador ){
					acessorio.append(" \t ["+(i+1)+"]"+ Acessorio.values()[indices[i]].getDescricao()+"\n");
				}
			}
			acessorio.append(" \t ["+(contador+1)+"]"+"ENCERRA CADASTRO\n");
			
			while(true){
				
				System.out.println(Mensagem.FORMULARIO_ACESSORIOS);
							
				int escolhida = escolherOpcao(acessorio.toString(), contador+1);

				if(escolhida == contador+1){
					break;
				}
				else{
					Acessorio acessor = Acessorio.values()[indices[escolhida - 1]];
					acessorios.add(acessor);
					System.out.println("\n \t Acessorio "+acessor.getDescricao()+" adicionado com sucesso.");
				}
			}
			try{
				novo.setAcessorios(acessorios);
				break;
			}
			catch (Exception e){
				System.out.println(e.getMessage());
			}
		}

		while (true){
			//----Pede Data de aquisicao----//
			System.out.println(" \t ---Informe a data da aquisicao---");
			int dia = retornaInteiroCorreto(Mensagem.FORMULARIO_DIA);
			int mes = Mes.values()[escolherOpcao(Mensagem.FORMULARIO_MES + listarObjetosNoArray(Mes.values()), Mes.values().length) - 1].getNumero();
			int anoData = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
			try{
				dataDeAquisicao = new Data(dia, mes, anoData);
				novo.setDataDeAquisicao(dataDeAquisicao);
				break;
			}
			catch (Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		//----Pede Cor----//
		cor = cores[escolherOpcao("\n \t -- Informe a cor do veiculo --\n" + listarObjetosNoArray(cores), cores.length) - 1];
		novo.setCor(cor);
		
		//----Pede tipo de combustivel----//
		tipoDeCombustivel = tiposDeCombustivel[escolherOpcao("\n\t-- Informe o tipo de combustivel --\n" + listarObjetosNoArray(tiposDeCombustivel), tiposDeCombustivel.length) - 1];
		novo.setTipoDeCombustivel(tipoDeCombustivel);

		while (true){
			//----Pede nivelDoTanque----//
			nivelDoTanque = retornaInteiroCorreto(Mensagem.FORMULARIO_NIVEL_DO_TANQUE);
			try{
				novo.setNivelDoTanque(nivelDoTanque);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}
		
		//----Pede Estado do veiculo----//
		int[] indices = new int[Estado.values().length];
		int contador = 0;
		
		String estado = "";
		for(int i=0; i < Estado.values().length;i++){
			if ( !(Estado.values()[i] == Estado.ALUGADO) ){
				indices[contador] = i;
				contador++;
			}
		}
		
		for ( int i=0; i<indices.length; i++ ){
			if ( i<contador ){
				estado += " \t ["+(i+1)+"]"+ Estado.values()[indices[i]]+"\n";				
			}
		}

		int escolhida = escolherOpcao(Mensagem.FORMULARIO_ESTADOS+estado, contador);
		Estado estadoDoVeiculo = Estado.values()[indices[escolhida - 1]];
		novo.setEstado(estadoDoVeiculo);

		while (true){
			//----Pede cilindradas----//
			cilindradas = retornaInteiroCorreto(Mensagem.FORMULARIO_CILINDRADAS);
			try{
				novo.setCilindradas(cilindradas);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}
		}

		//----Pede tipo de freio----//
		tipoDeFreio = tiposDeFreio[escolherOpcao("\n\t-- Informe o tipo de freio --\n" + listarObjetosNoArray(tiposDeFreio), tiposDeFreio.length) - 1];
		novo.setTipoDeFreio(tipoDeFreio);
		
		//Tenta construir adicionar
		adicionaObjetoNaLista(motocicletasLista, novo);
		geradorDeLog.escreveLog("Motocicleta de placa "+novo.getPlaca()+" e  RENAVAM "+novo.getRenavam()+" cadastrado");
	}
	
	private static void excluirAutomovel() throws Exception{
		
		int contador=0;
		
		int indice=0;
		
		int[] indices = new int[automoveisLista.size()];
		
		Iterator<Veiculo> iterador = automoveisLista.iterator();
		
		String format = "";
		while(iterador.hasNext()){
			Veiculo objeto = iterador.next();
			if( objeto instanceof Automovel){
				format += "\n \t ["+(contador+1)+"]\n"+objeto;
				indices[contador] = indice;
				contador++;
			}
			indice++;
		}

		format += "\n \t ["+(contador+1)+"]VOLTAR";
		
		if ( (contador) == 0 ){
			throw new Exception(Mensagem.MENSAGEM_NAO_HA_MAIS_DESSE_TIPO);
		}

		System.out.println("\t\t========================");
		System.out.println("\t\t Excluindo Automovel");
		System.out.println("\t\t========================");
		
		int escolhido = escolherOpcao(format+"\n \t Selecione o Automovel a ser excluido: ", contador+1);

		if ( escolhido == (contador+1) ){
			throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
		}

		geradorDeLog.escreveLog("Automovel de placa "+automoveisLista.get(indices[escolhido-1]).getPlaca()+" e RENAVAM "+automoveisLista.get(indices[escolhido-1]).getRenavam() +"excluido");
		automoveisLista.remove(indices[escolhido-1]);
		
	}//Fim de excluirAutomovel

	private static void excluirMotocicleta() throws Exception{
		
		int contador=0;
		
		int indice=0;
		
		int[] indices = new int[motocicletasLista.size()];
		
		Iterator<Veiculo> iterador = motocicletasLista.iterator();
		
		String format = "";
		while(iterador.hasNext()){
			Veiculo objeto = iterador.next();
			if( objeto instanceof Motocicleta){
				format += "\n \t ["+(contador+1)+"]\n"+objeto;
				indices[contador] = indice;
				contador++;
			}
			indice++;
		}

		format += "["+(contador+1)+"]VOLTAR";
		
		if ( contador == 0 ){
			throw new Exception(Mensagem.MENSAGEM_NAO_HA_MAIS_DESSE_TIPO);
		}

		System.out.println("\t\t========================");
		System.out.println("\t\t Excluindo Motocicleta");
		System.out.println("\t\t========================");
		
		int escolhido = escolherOpcao(format+"\n \t Selecione a Motocicleta a ser excluida: ", contador+1);
		
		if ( escolhido == (contador+1) ){
			throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
		}

		geradorDeLog.escreveLog("Motocicleta de placa "+motocicletasLista.get(indices[escolhido-1]).getPlaca()+" e RENAVAM "+motocicletasLista.get(indices[escolhido-1]).getRenavam() +"excluido");
		motocicletasLista.remove(indices[escolhido-1]);
		
	}//Fim de excluirMotocicleta
	
	private static void excluirLocador() throws Exception{
		
		int contador=0;
		
		int indice=0;
		
		int[] indices = new int[usuariosLista.size()];
		
		Iterator<Locador> iterador = usuariosLista.iterator();
		
		String format = "";
		while(iterador.hasNext()){
			Locador objeto = iterador.next();
			if( !(objeto == root) ){
				format+="\n \t ["+(contador+1)+"]\n"+objeto;
				indices[contador] = indice;
				contador++;
			}
			indice++;
		}
		format+="\n \t ["+(contador+1)+"]VOLTAR";
		
		if ( contador == 0 ){
			throw new Exception(Mensagem.MENSAGEM_NAO_HA_MAIS_DESSE_TIPO);
		}
		
		System.out.println("\t\t========================");
		System.out.println("\t\t Excluindo Locador");
		System.out.println("\t\t========================");
		
		System.out.println(format);
		
		int escolhido = escolherOpcao("\n \t Selecione o funcionario a ser excluido: ", contador+1);
		
		if ( escolhido == (contador+1) ){
			throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
		}

		geradorDeLog.escreveLog("Usuario "+usuariosLista.get(indices[escolhido-1]).getLogin()+" excluido");
		usuariosLista.remove(indices[escolhido-1]);
		
	}//Fim de excluirUsuario
	
	public static void cadastrarLocador() throws Exception {

		System.out.println("\t\t========================");
		System.out.println("\t\t Cadastrando Locador");
		System.out.println("\t\t========================");

		Locador novo = new Locador();
		
		while (true) {
			// Pede nome
			String nome = retornaStringCorreto(Mensagem.FORMULARIO_NOME);
			try{
				novo.setNome(nome);
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true) {
			// Pede telefone
			String telefone = retornaStringCorreto(Mensagem.FORMULARIO_TELEFONE);
			try{
				novo.setTelefone(telefone);
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true) {
			// Pede e-mail
			String email = retornaStringCorreto(Mensagem.FORMULARIO_EMAIL);
			try{
				novo.setEmail(email);
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while ( true ){
			
		
			while (true) {
				try{
					// Pede CPF
					String cpf = retornaStringCorreto(Mensagem.FORMULARIO_CPF);
					novo.setCPF(cpf);
					break;
				}
				catch(Exception e){
					if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
						throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
					}
					System.out.println(e.getMessage());
				}
			}
			
			try{
				// Pede RG
				String rg = retornaStringCorreto(Mensagem.FORMULARIO_RG);
				novo.setRG(rg);
				validaExistencia(usuariosLista, novo, "\n \t <Esse CPF ou RG ja foi cadastrado!>");
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while ( true ){
			System.out.println("\n\t---Data de Nascimento---");
			
			// Pede Dia de Nascimento
			int diaDeNascimento = retornaInteiroCorreto(Mensagem.FORMULARIO_DIA);
			
			// Pede Mes de Nascimento
			int mesDeNascimento = Mes.values()[escolherOpcao(Mensagem.FORMULARIO_MES + listarObjetosNoArray(Mes.values()), Mes.values().length) - 1].getNumero();
			
			// Pede Ano de Nascimento
			int anoDeNascimento = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
			
			try{
				Data novaData = new Data(diaDeNascimento, mesDeNascimento, anoDeNascimento);

				if ( (new Data()).getAno() - novaData.getAno() < Constantes.IDADE_MINIMA_LOCADOR ){
					System.out.println("\n \t <Locador deve ter mais de "+Constantes.IDADE_MINIMA_LOCADOR+" anos!>");
					continue;
				}
				
				novo.setDataDeNascimento(novaData);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		while (true) {
			// Pede Naturalidade
			String naturalidade = retornaStringCorreto(Mensagem.FORMULARIO_NATURALIDADE);
			try{
				novo.setNaturalidade(naturalidade);
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		while (true) {
			try{
				// Pede Login
				String login = retornaStringCorreto(Mensagem.FORMULARIO_LOGIN);
				novo.setLogin(login);
				validaExistencia(usuariosLista, novo, "\n \t <Esse login ja foi cadastrado!>");
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		while (true) {
			// Pede Senha
			String senha = retornaSenha(Mensagem.FORMULARIO_SENHA);
			String autenticacao = retornaSenha(Mensagem.FORMULARIO_SENHA_AUTENTICACAO);
			try{
				if ( !senha.equals(autenticacao) ){
					throw new Exception(Mensagem.FORMULARIO_FALHA_AUTENTICACAO);
				}
				novo.setSenha(senha);
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		novo.setEhGerente(false);
		
		Endereco enderecoDoLocador = cadastraEndereco();
		novo.setEndereco(enderecoDoLocador);
		
		adicionaObjetoNaLista(usuariosLista, novo);
		geradorDeLog.escreveLog("Usuario "+novo.getLogin()+" Matricula "+novo.getMatricula()+" cadastrado");
	}
	
	public static void editaGerente() throws Exception {

		System.out.println("\t\t========================");
		System.out.println("\t\t Editando Gerente");
		System.out.println("\t\t========================");
		
		while (true) {
			try{
				// Pede nome
				String nome = retornaStringCorreto(Mensagem.FORMULARIO_NOME);
				root.setNome(nome);
				geradorDeLog.escreveLog("Gerente teve seu nome modificado para "+root.getNome());
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		usuariosLista.remove(root);
		
		while (true) {
			try{
				// Pede Login
				String login = retornaStringCorreto(Mensagem.FORMULARIO_LOGIN);
				root.setLogin(login);
				validaExistencia(usuariosLista, root, "\n \t <Esse login ja foi cadastrado!>");
				geradorDeLog.escreveLog("Gerente teve seu login modificado para "+root.getLogin());
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					usuariosLista.add(root);
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		usuariosLista.add(root);
		
		while (true) {
			// Pede Senha
			String senha = retornaSenha(Mensagem.FORMULARIO_SENHA);
			String autenticacao = retornaSenha(Mensagem.FORMULARIO_SENHA_AUTENTICACAO);
			try{
				if ( !senha.equals(autenticacao) ){
					throw new Exception(Mensagem.FORMULARIO_FALHA_AUTENTICACAO);
				}
				root.setSenha(senha);
				geradorDeLog.escreveLog("Gerente teve sua senha modificada");
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		root.setEhGerente(true);
		
		while (true) {
			// Pede telefone
			String telefone = retornaStringCorreto(Mensagem.FORMULARIO_TELEFONE);
			try{
				root.setTelefone(telefone);
				geradorDeLog.escreveLog("Gerente teve seu telefone modificado");
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true) {
			// Pede e-mail
			String email = retornaStringCorreto(Mensagem.FORMULARIO_EMAIL);
			try{
				root.setEmail(email);
				geradorDeLog.escreveLog("Gerente teve seu email modificado para "+root.getEmail());
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		usuariosLista.remove(root);
		
		while ( true ){
			
		
			while (true) {
				try{
					// Pede CPF
					String cpf = retornaStringCorreto(Mensagem.FORMULARIO_CPF);
					root.setCPF(cpf);
					break;
				}
				catch(Exception e){
					if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
						usuariosLista.add(root);
						throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
					}
					System.out.println(e.getMessage());
				}
			}

			try{
				// Pede RG
				String rg = retornaStringCorreto(Mensagem.FORMULARIO_RG);
				root.setRG(rg);
				validaExistencia(usuariosLista, root, "\n \t <Esse CPF ou RG ja foi cadastrado!>");
				geradorDeLog.escreveLog("Gerente teve seu RG e CPF modificados");
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					usuariosLista.add(root);
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		usuariosLista.add(root);
		
		while ( true ){
			System.out.println("\n\t---Data de Nascimento---");
			
			// Pede Dia de Nascimento
			int diaDeNascimento = retornaInteiroCorreto(Mensagem.FORMULARIO_DIA);
			
			// Pede Mes de Nascimento
			int mesDeNascimento = Mes.values()[escolherOpcao(Mensagem.FORMULARIO_MES + listarObjetosNoArray(Mes.values()), Mes.values().length) - 1].getNumero();
			
			// Pede Ano de Nascimento
			int anoDeNascimento = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
			
			try{
				Data novaData = new Data(diaDeNascimento, mesDeNascimento, anoDeNascimento);

				if ( (new Data()).getAno() - novaData.getAno() < Constantes.IDADE_MINIMA_LOCADOR ){
					System.out.println("\n \t <Gerente deve ter mais de "+Constantes.IDADE_MINIMA_LOCADOR+" anos!>");
					continue;
				}
				
				root.setDataDeNascimento(novaData);
				geradorDeLog.escreveLog("Gerente teve sua data de nascimento modificada para "+root.getDataDeNascimento().getData());
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		Endereco enderecoDoGerente = cadastraEndereco();
		root.setEndereco(enderecoDoGerente);
		geradorDeLog.escreveLog("Gerente teve seu endereco modificado");
		
		while (true) {
			// Pede Naturalidade
			String naturalidade = retornaStringCorreto(Mensagem.FORMULARIO_NATURALIDADE);
			try{
				root.setNaturalidade(naturalidade);
				geradorDeLog.escreveLog("Gerente teve sua naturalidade modificada para "+root.getNaturalidade());
				break;
			}
			catch(Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		geradorDeLog.escreveLog("Gerente "+root.getNome()+ " de login "+root.getLogin()+" foi totalmente modificado");
	}
	
	private static void editaAgencia() throws Exception{
		
		System.out.println("\t\t==================");
		System.out.println("\t\t Editando Agencia");
		System.out.println("\t\t==================");
		
		while (true){
			try{
				String nomeFantasia = retornaStringCorreto(Mensagem.FORMULARIO_NOME_FANTASIA);
				agenciaAtual.setNomeFantasia(nomeFantasia);
				geradorDeLog.escreveLog("Agencia teve seu nome de fantasia modificado para "+nomeFantasia);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

			
		while (true){
			try{
				String cnpj = retornaStringCorreto(Mensagem.FORMULARIO_CNPJ);
				agenciaAtual.setCNPJ(cnpj);
				geradorDeLog.escreveLog("Agencia teve seu CNPJ modificado");
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true){
			try{
				String inscricaoEstadual = retornaStringCorreto(Mensagem.FORMULARIO_INSC_ESTADUAL);
				agenciaAtual.setInscricaoEstadual(inscricaoEstadual);
				geradorDeLog.escreveLog("Agencia teve sua inscricao estadual modificado");
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
			
		}
		
		while (true){
			try{
				String razaoSocial = retornaStringCorreto(Mensagem.FORMULARIO_RAZAO_SOCIAL);
				agenciaAtual.setRazaoSocial(razaoSocial);
				geradorDeLog.escreveLog("Agencia teve sua razao social modificada para "+razaoSocial);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			try{
				String telefone = retornaStringCorreto(Mensagem.FORMULARIO_TELEFONE);
				agenciaAtual.setTelefone(telefone);
				geradorDeLog.escreveLog("Agencia teve seu telefone modificado");
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true){
			try{
				String email = retornaStringCorreto(Mensagem.FORMULARIO_EMAIL);
				agenciaAtual.setEmail(email);
				geradorDeLog.escreveLog("Agencia teve seu email modificado para "+email);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		Endereco enderecoDaAgencia = cadastraEndereco();
		agenciaAtual.setEndereco(enderecoDaAgencia);
		geradorDeLog.escreveLog("Agencia teve seu endereco modificado");
		geradorDeLog.escreveLog("Agencia "+agenciaAtual.getNomeFantasia()+ " foi totalmente modificada");
	}
	
	public static void cadastraClienteFisico() throws Exception{

		System.out.println("\t\t====================================");
		System.out.println("\t\t Cadastrando Cliente Pessoa Fisica");
		System.out.println("\t\t====================================");
		
		ClienteFisico novo = new ClienteFisico();

		while (true){
			try{
				// Pede nome
				String nome = retornaStringCorreto(Mensagem.FORMULARIO_NOME);
				novo.setNome(nome);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true){
			try{
				// Pede telefone
				String telefone = retornaStringCorreto(Mensagem.FORMULARIO_TELEFONE);
				novo.setTelefone(telefone);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true){
			try{
				// Pede e-mail
				String email = retornaStringCorreto(Mensagem.FORMULARIO_EMAIL);
				novo.setEmail(email);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while ( true ) {
		
			while (true){
				try{
					// Pede CPF
					String cpf = retornaStringCorreto(Mensagem.FORMULARIO_CPF);
					novo.setCPF(cpf);
					break;
				}
				catch (Exception e){
					if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
						throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
					}
					System.out.println(e.getMessage());
				}
			}
	
			try{
				// Pede RG
				String rg = retornaStringCorreto(Mensagem.FORMULARIO_RG);
				novo.setRG(rg);
				validaExistencia(clientesFisicosLista, novo, "\n \t <Esse CPF ou RG ja foi cadastrado!>");
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		while ( true ){
			System.out.println("\n \t ---Informe a data de nascimento---");
			// Pede Dia de Nascimento
			int diaDeNascimento = retornaInteiroCorreto(Mensagem.FORMULARIO_DIA);
			// Pede Mes de Nascimento
			int mesDeNascimento = Mes.values()[escolherOpcao(Mensagem.FORMULARIO_MES + listarObjetosNoArray(Mes.values()), Mes.values().length) - 1].getNumero();
			// Pede Ano de Nascimento
			int anoDeNascimento = retornaInteiroCorreto(Mensagem.FORMULARIO_ANO);
			
			try{
				Data dataNascimento = new Data(diaDeNascimento, mesDeNascimento, anoDeNascimento);

				if ( (new Data()).getAno() - dataNascimento.getAno() < Constantes.IDADE_MINIMA_CLIENTE ){
					System.out.println("\n \t <Cliente deve ter mais de "+Constantes.IDADE_MINIMA_CLIENTE+" anos!>");
					continue;
				}
				
				novo.setDataDeNascimento(dataNascimento);
				break;
			}
			catch(Exception e){
				System.out.println(e.getMessage());
			}

		}

		Endereco endereco = cadastraEndereco();
		novo.setEndereco(endereco);
		
		while (true){
			try{
				// Pede Naturalidade
				String naturalidade = retornaStringCorreto(Mensagem.FORMULARIO_NATURALIDADE);
				novo.setNaturalidade(naturalidade);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		adicionaObjetoNaLista(clientesFisicosLista, novo);
		geradorDeLog.escreveLog("Cliente pessoa fisica de nome "+novo.getNome()+" cadastrado");
	}
	
	public static void cadastraClienteJuridico() throws Exception{

		System.out.println("\t\t======================================");
		System.out.println("\t\t Cadastrando Cliente Pessoa Juridica");
		System.out.println("\t\t======================================");
		
		ClienteJuridico novo = new ClienteJuridico();
		
		while (true){
			try{
				// Pede nome
				String nome = retornaStringCorreto(Mensagem.FORMULARIO_NOME_FANTASIA);
				novo.setNomeFantasia(nome);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true){
			try{
				// Pede telefone
				String telefone = retornaStringCorreto(Mensagem.FORMULARIO_TELEFONE);
				novo.setTelefone(telefone);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while (true){
			try{
				// Pede e-mail
				String email = retornaStringCorreto(Mensagem.FORMULARIO_EMAIL);
				novo.setEmail(email);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		while ( true ){
		
			while (true){
				try{
					//Pede cnpj
					String cnpj = retornaStringCorreto(Mensagem.FORMULARIO_CNPJ);
					novo.setCNPJ(cnpj);
					break;
				}
				catch (Exception e){
					if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
						throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
					}
					System.out.println(e.getMessage());
				}
			}

			try{
				//Pede Inscricao Estadual
				String inscricaoEstadual = retornaStringCorreto(Mensagem.FORMULARIO_INSC_ESTADUAL);
				novo.setInscricaoEstadual(inscricaoEstadual);
				validaExistencia(clientesJuridicosLista, novo, "\n \t <Esse CPNJ ou inscricao estadual ja foi cadastrado!>");
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}
		
		while (true){
			try{
				//Pede Razao Social
				String razaoSocial = retornaStringCorreto(Mensagem.FORMULARIO_RAZAO_SOCIAL);
				novo.setRazaoSocial(razaoSocial);
				break;
			}
			catch (Exception e){
				if ( e.getMessage().equals(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO) ){
					throw new Exception(Mensagem.MENSAGEM_CANCELADO_PELO_USUARIO);
				}
				System.out.println(e.getMessage());
			}
		}

		Endereco enderecoDoCliente = cadastraEndereco();
		novo.setEndereco(enderecoDoCliente);
		
		adicionaObjetoNaLista(clientesJuridicosLista, novo);
		geradorDeLog.escreveLog("Cliente pessoa juridica de nome "+novo.getNome()+" cadastrado");
	}
	
	@SuppressWarnings("unchecked")
	private static void validaExistencia( List lista, Object aSerAdicionado, String alerta) throws Exception{
		
		if ( !lista.isEmpty() ){
			System.out.println("\n \t Validando existencia de "+aSerAdicionado.getClass().getSimpleName()+"...");

			Iterator iterador = lista.iterator();
			
			while(iterador.hasNext()){
					
				if ( iterador.next().equals(lista.get(0).getClass().cast(aSerAdicionado)) ){
					throw new Exception(alerta);
				}
			}
/*			while(iterador.hasNext()){
				
				if ( lista.get(0).getClass().getSuperclass().cast(iterador.next()).equals(lista.get(0)
						.getClass().getSuperclass().cast(aSerAdicionado) ) ){
					throw new Exception(alerta);
				}
					
			} PARA QUANDO HAVIA LISTA DE VEICULOS COM MOTOS E CARROS MISTURADOS*/

		}
		
	}
	
	public static Locador getRoot(){
		return root;
	}
	
	public static String getComandoDeRetorno(){
		return comando_retorno;
	}
}